Java内部类的学习与理解

内部类的定义是将一个类的定义放在另一个类的定义内部,这就是内部类。

而我们知道,外部类只能用public和default来修饰,但是内部类就不受这个限制,可以用private和protected。而且内部类写起来也很简单:

PS: 附上.this和.new用法。

public class Outer {
    private String name;
    public Outer(String name) {
        this.name = name;
        System.out.println("我是外部类");
    }

    private class Inner{
        public void show(){
            System.out.println("我是内部类");
        }
        public String name(){//如果你需要生成对外部类的引用,可以使用外部类的名字后面紧跟.this
            return "从内部类调用:外部类属性name = " + Outer.this.name;
        }
    }

    public Inner inner(){
        return new Inner();
    }

    public static void main(String[] args){
        Outer o = new Outer("外部类");
        Inner i = o.new Inner();//用其它对象来创建某个内部类对象用.new语法
        System.out.println(i.name());
    }

但是为什么我们要使用内部类呢?

  1. 内部类方法可以访问该类定义所在作用域中的数据,包括被 private 修饰的私有数据
  2. 内部类可以对同一包中的其他类隐藏起来(通过private 与 protected)
  3. 内部类可以实现多重继承,弥补java单继承缺陷。
  4. 当我们想要定义一个回调函数却不想写大量代码的时候我们可以选择使用匿名内部类来实现

下面我们逐一来理解这4点:

1、当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用,此外,内部类还拥有其外围类的所有元素的访问权。

看一个迭代器设计例子:

public interface Selector {
    boolean end();
    Object current();
    void next();
}
public class Sequence {
    private Object[] items;
    private int next = 0;
    public Sequence(int size) {
        this.items = new Object[size];
    }
    public void add(Object x){
        if(next < items.length){
            items[next++] = x;
        }
    }
    private class SequenceSelector implements Selector{
        private int i = 0;
        @Override
        public boolean end() {
            return i == items.length;
        }
        @Override
        public Object current() {
            return items[i];
        }
        @Override
        public void next() {
            if(i < items.length)i++;
        }
    }
    public Selector selector(){
        return new SequenceSelector();
    }

    //当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密的捕获一个指向那个外围类对象的引用
    public static void main(String[] args){
        Sequence sequence = new Sequence(10);
        for (int i = 0; i< 10 ; i++){
            sequence.add(Integer.toString(i));
        }

        Selector selector = sequence.selector();
        while(!selector.end()){
            System.out.print(selector.current() + " ");
            selector.next();
        }
       
}

2、第二点很简单,理解权限修饰符即可

3、Thinking in Java中:

使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

内部类存在的意义——实现多重继承

//类一
public class A{
   public String name(){
       return "your name";
   }
   public String doSomeThing(){
    // doSomeThing
   }
}
//类二
public class B{
    public int age(){
        return 25;
    }
}

//类三
public class MainExample{
   private class Test1 extends A{
        public String name(){
          return super.name();
        }
    }
    private class Test2 extends B{
       public int age(){
         return super.age();
       }
    }
   public String name(){
    return new Test1().name();
   }
   public int age(){
       return new Test2().age();
   }
   public static void main(String args[]){
       MainExample mi=new MainExample();
       System.out.println("姓名:"+mi.name());
       System.out.println("年龄:"+mi.age());
   }
}

每个内部类都可以队里的继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类没有影响 如果没有内部类提供的、可以继承多个具体的或抽象的类的能力,一些设计与编程问题就难以解决。 接口解决了部分问题,一个类可以实现多个接口,内部类允许继承多个非接口类型(类或抽象类)。

Java只能继承一个类这个学过基本语法的人都知道,而在有内部类之前它的多重继承方式是用接口来实现的。但使用接口有时候有很多不方便的地方。比如我们实现一个接口就必须实现它里面的所有方法。而有了内部类就不一样了。它可以使我们的类继承多个具体类或抽象类。

4、我们先来捋捋Java中回调函数的两个基本条件

* 1.Class A调用Class B中的X方法

* 2.ClassB中X方法执行的过程中调用Class A中的Y方法完成回调

再来用匿名内部类来实现回调,这里写一个利用回调来计算对象执行方法耗时的工具

public interface CallBack {
    void excute();//实例对象执行某个方法
}

public class Student implements CallBack {
    private Integer sum = 500;//学生算算术
    @Override
    public void excute() {
        int i = 0;
        while(i < sum ){
            System.out.print(i + ",");
            i++;
        }
        System.out.println();
    }
}

public class TimeTool {//时间工具类

    public void testTime(CallBack callBack){
        long begin = System.currentTimeMillis();
        callBack.excute();//执行回调
        long end = System.currentTimeMillis();
        long usedTime = end - begin;
        System.out.println(callBack.getClass().getName() + "耗时: " + usedTime);
    }

}

public class Test {//测试类
    public static void main(String[] args){
        TimeTool timeTool = new TimeTool();
        
        timeTool.testTime(new Student());

        timeTool.testTime(new CallBack(){//使用匿名内部类来回调
            @Override
            public void excute() {
                //someClass.dosomething()
                int i = 0;
                while(i < 500){
                    System.out.print(i + ",");
                    i++;
                }
                System.out.println();
            }
        });

        
    }
}

参考https://juejin.im/post/5a903ef96fb9a063435ef0c8

 

 

你可能感兴趣的:(Java基础)