跳至主要內容

内部类

wangdx大约 10 分钟

内部类

内部类基本定义

在一个类之中基本的组成就是成员属性或者是方法,而在一个类中也可以包含有另外-个类,这样的程序逻辑结构所带来的最直接的优势在于:可以方便的实现外部类中私有成员的访问

class 外部类{
  外部类成员属性;
  外部类方法
  class 内部类{
    外部类成员属性;
    外部类方法
    class 内部类{}
  }
}
案例
public class Outer {
    private String message = "一祥集团:www.yix.com";

    public void fun() {
        new Inner().printMessage();
    }

    class Inner {
        public void printMessage() {
            System.out.println(message);
        }
    }
}

class Test {
    public static void main(String[] args) {
        new Outer().fun();
    }
}

拆分分析

public class Outer {
    private String message;

    public void fun() {
        new Inner(this).printMessage();
    }

    public String getMessage() {
        return message;
    }
}

class Inner {
    private Outer outer;

    public Inner(Outer outer) {
        this.outer = outer;
    }

    public void printMessage() {
        System.out.println(this.outer.getMessage());
    }
}

static 定义内部类

在一个类结构之中,static 关键字可以定义公共属性、公共的方法以及内部类,之所以使用 static 主要的目的是不受到实例化对象的限,而如果在一个内部类上使用了 static, 那么本质上就相当于这个类就成为了一个外部类。

案例
public class Outer {
    private static final String MESSAGE = "一祥集团:www.yix.com";

    //使用了static关键字,所以这个类就成了外部类 可以使用new INNer()
    static class Inner {
        public void printMessage() {
            System.out.println(Outer.MESSAGE);
        }
    }
}

class Test {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        inner.printMessage();
    }
}
/*
 * 外部接口定义
 * */
interface IMessage {
    public void send(String message);

    public static IChannel getDefaultChannel() {
        return new InternetChannel();
    }

    public static AbstractHandle getDefaultHandle() {
        return new MessageHandle();
    }

    static interface IChannel {
        public boolean build();

        public void close();
    }

    static abstract class AbstractHandle {
        public abstract String addPrefix(String value);
    }

    class InternetChannel implements IMessage.IChannel {

        @Override
        public boolean build() {
            System.out.println("创建连接");
            return true;
        }

        @Override
        public void close() {
            System.out.println("关闭连接");
        }
    }

    class MessageHandle extends IMessage.AbstractHandle {

        @Override
        public String addPrefix(String value) {
            return "一祥集团" + value;
        }
    }
}

class NetMessage implements IMessage {

    @Override
    public void send(String message) {
        IChannel channel = IMessage.getDefaultChannel();
        AbstractHandle handle = new NewMessageHandle();
        if (channel.build()) {
            System.out.println(handle.addPrefix(message));
            channel.close();
        }
    }
}

class NewMessageHandle extends IMessage.AbstractHandle {

    @Override
    public String addPrefix(String value) {
        return "李兴华编程" + value;
    }
}

class Test1 {
    public static void main(String[] args) {
        IMessage message = new NetMessage();
        message.send("www.yix.com");
    }
}

创建连接
李兴华编程www.yix.com
关闭连接

方法中定义内部类

案例

/**
 * 方法中定义内部类
 * @author wangdx
 */
public interface IMessage {
    public void send(String message);

    public static IMessage getDefaultMessage(String prefix) {
        class MessageImpl implements IMessage {

            @Override
            public void send(String message) {
                System.out.println("【" + prefix + "】" + message);
            }
        }
        return new MessageImpl();
    }
}

class Test {
    public static void main(String[] args) {
        IMessage message = IMessage.getDefaultMessage("沐言科技");
        message.send("李兴华编程训练营");
    }
}

【沐言科技】李兴华编程训练营

匿名内部类

案例
/**
 * 匿名内部类
 *
 * @author wangdx
 */
public interface IMessage {
    public String echo(String msg);
}

class Test {
    public static void main(String[] args) {
        IMessage message = new IMessage() {
            @Override
            public String echo(String msg) {
                return "一祥集团" + msg;
            }
        };
        System.out.println(message.echo("www.yix.com"));
    }
}

一祥集团www.yix.com

Lambda 表达式

  • Lambda 表达式是 JDK1.8 中引入的重要技术特征。所谓的 Lambda 表达式指的是应用在“SAM"(Single Abstract Method,含有一个抽象方法的接口)环境下的一种简化定义形式,可以解决匿名内部类的定义复杂问题,在 Java 中 Lambda 表达式的基本语法形式如下:
- 定义方法体:(参数, 参数..)->{方法体}
- 直接返回结果:(参数,参数...) ->语句
  • 在 Lambda 表达式中定义的参数与要实现接口中抽象方法定义的参数类型及个数相同如果方法体代码很多,则可以使用“”定义,如果仅仅是返回一个简单的执行结果那么直接编写单个表达式即可。
案例
/**
 * 使用lambda表达式代替匿名类
 *
 * @author wangdx
 */
@FunctionalInterface
public interface IMessage {
    public String echo(String msg);
}

class Test {
    public static void main(String[] args) {
        IMessage message = (str) -> "【一祥集团】" + str;
        System.out.println(message.echo("www.yix.xom"));
    }
}

【一祥集团】www.yix.xom
/*
 * 使用lambda表达式多行代码
 * */
class Test1 {
    public static void main(String[] args) {
        IMessage message = (str) -> {
            if (str.contains("yootk")) {
                return "【沐言科技】" + str;
            } else {
                return "【消息回应】" + str;
            }
        };
        System.out.println("www.yootk.com");
        System.out.println("一祥集团-王大祥");
    }
}

www.yootk.com
一祥集团-王大祥

方法引用

在 Java 中利用对象的引用传递可以实现不同的对象名称操作同一块堆内存空间的操作,而从 JDK 1.8 开始,对于方法上也支持了引用操作,这样就相当于为方法定义了别名,对于方法引用的形式一共有如下四种:

  • 引用静态方法: 类名称::static 方法名称;
  • 引用某个对象的方法:实例化对象::普通方法;
  • 引用特定类型的方法:特定类::普通方法;
  • 引用构造方法:类名称::new。
案例
/**
 * 引用类的静态方法
 *
 * @author wangdx
 */
@FunctionalInterface
public interface IFunction<T> {
    public String convert(T value);
}

class Test {
    public static void main(String[] args) {
        IFunction<Integer> function = String::valueOf;
        String str = function.convert(989);
        System.out.println(str.length());
    }
}
@FunctionalInterface
interface IFunction1{
    public String upper();
}
/*
* 引用类普通方法
* */
class Test1{
    public static void main(String[] args) {
        IFunction1 function = "沐言科技:www.yix.com"::toUpperCase;
        System.out.println(function.upper());
    }
}
/*
 * 引用特定类普通方法
 * */
@FunctionalInterface
interface IFunction2<P>{
    public int compare(P p1,P p2);
}

class Test2{
    public static void main(String[] args) {
        IFunction2<String> function = String::compareTo;
        System.out.println(function.compare("www.yix.com","www.YIX.com"));
    }
}
/*
 * 构造方法引用
 * */
class Book {
    private String title;
    private String author;
    private double price;

    public Book(String title, String author, double price) {
        this.title = title;
        this.author = author;
        this.price = price;
    }

    @Override
    public String toString() {
        return "【图书】图书名:" + this.title + "、图书作者" + this.author + "、图书价格:" + this.price;
    }
}

@FunctionalInterface
interface IFunction3<B> {
    public B create(String tempTitle, String tempAuthor, double tempPrice);
}

class Test3 {
    public static void main(String[] args) {
        IFunction3<Book> function3 = Book::new;
        System.out.println(function3.create("java入门到实战", "李兴华", 85.6));
    }
}

【图书】图书名:java入门到实战、图书作者李兴华、图书价格:85.6

内建函数式接口

案例
public class Test {
    public static void main(String[] args) {
        Predicate<String> predicate = "yix.com"::equalsIgnoreCase;
        System.out.println(predicate.test("YIX.COM"));
    }
}

链表

链表基本概念

在 Java 中利用对象数组可以实现若干个对象的共同存储,由于数组属于定长的数据结构这样就无法轻松的实现数据存储容量的扩充,而为了解决数组存储所带来的问题,就可以基于引用数据类型的特点通过链表形式结构实现多个对象的数据保存,这种设计结构类似于火车车厢的挂钩设计,如图所示,每一个火车车厢都可以保存有一个数据,而后若干个火车车厢可以通过固定的规则进行连接,理论上只要内存空间足够大,那么就可以挂载无限多个火车车厢,这样就可以保存无限多的数据内容,从而解决数组数据存储长度固定的问题。

链表基本结构

链表是一种常见的数据结构,在链表中所有的数据都被封装在节点之中,而后当前的节点都会保存有下一个节点的引用,如图所示。在进行数据操作时,所有的节点操作需要被专属的工具类包装,开发者无需知道 Node 数据的存储形式,只关心具体的数据操作。

案例
/**
 * 链表基本结构
 *
 * @author wangdx
 */
public interface ILink<T> {
}

class LinkImpl<T> implements ILink<T> {
    private class Node<T> {
        private T data;
        private Node<T> next;

        public Node(T data) {
            this.data = data;
        }
    }

    private Node<T> root;
}

class Test {
    public static void main(String[] args) {
        ILink<String> link = new LinkImpl<>();
    }
}

增加链表数据

在进行节点关联中最为重要的是根节点的配置,为了保证不重复设置根节点的引用,在引用配置前增加了一个根节点是否为空的判断"this.root == nul",在每次节点配置后需要同步修改 lastNode 引用

统计链表元素个数

链表的实现是为了动态数组的结构完善的,所以在这个时候就需要去随时获取链表里面对应元素的保存个数,这个功能就和在实际使用数组之中的“ength”属性类似,首先在 ILink 接口中扩充-一个获取数据长度的方法。

空链表判断

获取链表数据

所有的数据在链表中都是以节点引用的形式保存的,当客户端需要获取数据时就需要通过节点的递归操作的新娘更是进行处理,但是对于客户端来讲是不需要知道链表的具体实现细节的,即:客户端不需要知道 Node 节点的数据存储,所以就可以将链表中的数据以对象数组的形式返回

根据索引查询数据

链表是数组的一种功能结构扩展,由于链表中会存在有多个元素内容,同时这多个元素于是就需要提供有-都是按照一定的顺序进行存储的,一个根据索引获取数据内容的操作在链表中的数据索引获取可以利用迭代时的计数统计的方式来实现

案例

修改链表数据

链表数据查询

链表数据删除

清空链表数据

package innerClass.w09;

/**
 * 1.增加数据标准
 * 2.统计链表元素个数
 * 3.空链表判断
 * 4.获取链表数据
 * 5.根据索引获取数据
 * 6.根据索引修改数据值
 * 7.判断内容是否存在
 * 8.删除节点
 * 9.清空链表数据
 *
 * @author wangdx
 */
public interface ILink<T> {
    //增加数据保存,如果数据为null则不保存
    public void add(T data);

    //返回链表元素个数,没有则返回0
    public int size();

    //判断当前链表是否为空
    public boolean isEmpty();

    public Object[] toArray();

    public T get(int index);

    //如果存在数据返回修改前数据
    public T set(int index, T data);

    public boolean contains(T data);

    //返回指定内容,无法删除返回null
    public T remove(T data);

    public void clear();
}

class LinkImpl<T> implements ILink<T> {
    private Node<T> root;
    private Node<T> lastNode;
    private int count;

    @Override
    public void add(T data) {
        if (data == null) {
            return;
        }
        /*
         * 1.传进的数据本身没有顺序的,所以封装Node<T> newNode = new Node<>(data)
         * 2.需要确认保存节点位置,第一个节点应为根节点
         * */
        Node<T> newNode = new Node<>(data);
        if (this.root == null) {
            this.root = newNode;
            this.lastNode = newNode;
        } else {
            this.lastNode.next = newNode;
            this.lastNode = newNode;
        }
        this.count++;
    }

    @Override
    public int size() {
        return this.count;
    }

    @Override
    public boolean isEmpty() {
        return this.count == 0;
    }

    @Override
    public Object[] toArray() {
        if (this.isEmpty()) {
            return null;
        }
        Object[] returnData = new Object[this.count];
        int foot = 0;
        Node<T> node = this.root;
        while (node != null) {
            returnData[foot++] = node.data;
            node = node.next;
        }
        return returnData;
    }

    @Override
    public T get(int index) {
        if (index >= this.count || index < 0) {
            throw new ArrayIndexOutOfBoundsException("查询索引越界");
        }
        int foo = 0;
        Node<T> node = this.root;
        while (node != null) {
            if (index == foo++) {
                return (T) node.data;
            }
            node = node.next;
        }
        return null;
    }

    @Override
    public T set(int index, T data) {
        if (index >= this.count || index < 0) {
            throw new ArrayIndexOutOfBoundsException("索引越界");
        }
        T returnData = null;
        int foo = 0;
        Node<T> node = this.root;
        while (node != null) {
            if (index == foo++) {
                returnData = (T) node.data;
                node.data = data;
            }
            node = node.next;
        }
        return returnData;
    }

    @Override
    public boolean contains(T data) {
        if (this.root == null || data == null) {
            return false;
        }
        Node<T> node = this.root;
        while (node != null) {
            if (node.data.equals(data)) {
                return true;
            }
            node = node.next;
        }
        return false;
    }

    @Override
    public T remove(T data) {
        if (!this.contains(data)) {
            return null;
        }
        T returnData = null;
        if (this.root.data.equals(data)) {
            returnData = (T) this.root.data;
            this.root = this.root.next;
        } else {
            Node<T> parentNode = this.root;
            Node<T> node = this.root.next;
            while (node != null) {
                if (node.data.equals(data)) {
                    returnData = (T) node.data;
                    parentNode.next = node.next;
                    this.count--;
                }
                parentNode = node;
                node = node.next;
            }
        }
        return returnData;
    }

    @Override
    public void clear() {
        this.root = null;
        this.count = 0;
    }

    private class Node<T> {
        private T data;
        private Node<T> next;

        public Node(T data) {
            this.data = data;
        }
    }
}

class Test {
    public static void main(String[] args) {
        ILink<String> link = new LinkImpl<>();
        System.out.println(link.size());
        System.out.println(link.isEmpty());
        link.add("冬瓜");
        link.add("西瓜");
        link.add("南瓜");
        link.add("小香瓜");
        System.out.println(link.size());
        System.out.println(link.isEmpty());
        Object[] result = link.toArray();
        for (Object obj : result) {
            System.out.print(obj + "、");
        }
        System.out.println();
        System.out.println(link.get(1));
//        System.out.println(link.get(-1));
        System.out.println("【原始内容】" + link.set(2, "哈密瓜"));
        System.out.println("【修改后内容】" + link.get(2));
        System.out.println(link.contains("冬瓜"));
        System.out.println(link.contains("香香瓜"));
        System.out.println(link.remove("哈密瓜"));
        Object[] result1 = link.toArray();
        for (Object obj : result1) {
            System.out.print(obj + "、");
        }
        System.out.println();
    }
}

0
true
4
false
冬瓜、西瓜、南瓜、小香瓜、
西瓜
【原始内容】南瓜
【修改后内容】哈密瓜
true
false
哈密瓜
冬瓜、西瓜、小香瓜、
上次编辑于: