2021-10-04内部类

1.非静态成员内部类

public class OuterClass {
    //成员变量
    private String name;
    private int num = 10;
    //构造方法
    public OuterClass() {
    }
    public OuterClass(String name, int num) {
        this.name = name;
        this.num = num;
    }
    //成员方法
    public void methodOut(){
        System.out.println("methodOut");
    }
    public void methodOut2(){
        //外部类不可以直接访问内部的的成员变量和成员方法
        //System.out.println(type);
        //methodInner();
        InnerClass ic = new InnerClass();
        System.out.println(ic.num);//20
        ic.methodInner();
    }
    //内部类
    class InnerClass{
        //成员变量
        private String type;
        private int num = 20;
        //构造方法
        public InnerClass() {
        }
        public InnerClass(String type, int num) {
            this.type = type;
            this.num = num;
        }
        //成员方法
        public void methodInner(){
            //内部类可以直接访问外部类的成员变量
            System.out.println(name);
            int num = 30;
            System.out.println(num); //30
            System.out.println(this.num); //20
            //内部类如何访问外部类的同名成员变量
            System.out.println(OuterClass.this.num);//10
            methodOut();
        }
    }
}

public class Test {
    public static void main(String[] args) {
        OuterClass oc = new OuterClass();
        oc.methodOut();
        oc.methodOut2();
        //要创建 非静态成员内部类对象,必须先创建外部类的对象
        //OuterClass.InnerClass ic =   new OuterClass().new InnerClass();
        OuterClass oc2 = new OuterClass();
        OuterClass.InnerClass ic =oc2.new InnerClass();
    }
}

总结:基本特征

  1. 内部类可以直接访问外部类的成员
  2. 外部类不能直接访问内部类的成员,需要先创建对象再通过对象名访问
  3. 内部类如何访问外部类的同名成员变量:OuterClass.this.num
  4. 必须先创建外部类的对象,才能创建内部类的对象。非静态成员内部类是属于某个外部类对象的
  5. 非静态内部类不能有静态方法、静态属性和静态初始化块。
  6. 外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。

注意

内部类只是一个编译时概念,一旦我们编译成功,就会成为完全不同的两个类。对于一个名为Outer的外部类和其内部定义的名为Inner的内部类。编译完成后会出现Outer.class和Outer$Inner.class两个类的字节码文件。所以内部类是相对独立的一种存在,其成员变量/方法名可以和外部类的相同。

2. 静态成员内部类

public class OuterClass {
    //成员变量
    private static String name;
    private static int num = 10;
    //构造方法
    public OuterClass() {
    }
    public OuterClass(String name, int num) {
        this.name = name;
        this.num = num;
    }
    //成员方法
    public static void methodOut(){
        System.out.println("methodOut");
        InnerClass ic = new InnerClass();
        InnerClass.methodInner2();
    }
    public void methodOut2(){
        //外部类不可以直接访问内部的的成员变量和成员方法
        InnerClass ic = new InnerClass();
        System.out.println(ic.num);//20
        ic.methodInner();
        InnerClass.methodInner2();
    }
    //内部类
    static class InnerClass{
        //成员变量
        private String type;
        private int num = 20;
        //构造方法
        public InnerClass() {
        }
        public InnerClass(String type, int num) {
            this.type = type;
            this.num = num;
        }
        //成员方法
        public void methodInner(){
            //静态内部类只能够访问外部类的静态成员
            System.out.println(name);
            int num = 30;
            System.out.println(num); //30
            System.out.println(this.num); //20
            //静态内部类如何访问外部类的同名的成员变量
            System.out.println(OuterClass.num);//10
            methodOut();
        }
        public static  void methodInner2(){

        }
    }
}

public class Test {
    public static void main(String[] args) {
        //要创建静态成员内部类对象,不需要先创建外部类的对象
        OuterClass.InnerClass ic =new OuterClass.InnerClass();
        //需要import com.bjsxt.innerclass2.OuterClass.InnerClass;

   InnerClass ic2 = new InnerClass();
    }
}

总结:

  1. 静态内部类只能够访问外部类的静态成员
  2. 静态内部类如何访问外部类的同名的成员变量:OuterClass.num
  3. 静态内部类属于整个外部类的。创建静态内部类的对象,不需先创建外部类的对象
  4. 外部类可以通过类名直接访问内部类的静态成员,访问非静态成员依旧需要先创建内部类对象。

 3.局部内部类

它是定义在方法内部的,作用域只限于本方法,称为局部内部类。局部内部类的的使用主要是用来解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法中被使用,出了该方法就会失效。 局部内部类在实际开发中应用很少。

public class OuterClass {
    int num1 = 10;
    public void method(){
        int num2 = 20;
        class InnerClass{
            public void method2(){
                num1 = 100;
                System.out.println(num2);
                //num2 = 200;
            }
        }
        InnerClass ic = new InnerClass();
        ic.method2();
    }
}

注意:局部内部类访问所在方法的局部变量,要求局部变量必须使用final修饰。JDK1.8中final可以省略,但是编译后仍旧会加final。

4.匿名内部类(开发中使用较多)

匿名内部类就是内部类的简化写法,是一种特殊的局部内部类

前提:存在一个类或者接口,这里的类可以是具体类也可以是抽象类。

本质是什么呢?是一个继承了该类或者实现了该接口的子类匿名对象。

适合那种只需要创建一次对象的类。比如:Java GUI编程、Android编程键盘监听操作等等。比如Java开发中的线程任务Runnble、外部比较器Comparator等。

语法:

new  父类构造器(实参类表) \实现接口 () {

      //匿名内部类类体!

}

问题:一个类实现Comparable接口,只能指定一种比较大小的规则,如果需要有更多的比较规则,怎么办?

Comparable:内部比较器   public class Student implements Comparable{} 内部比较器只能有一个,一般采用最经常使用的比较规则

Comparator 外部比较器  可指定多个 不需要Student实现该接口,而是定义专门的类。

(1)定义Comparator接口

public interface Comparator{
    /**
     * 比较两个对象的大小
     * @param obj1
     * @param obj2
     * @return
     * <0  小于
     * =0  等于
     * >0 大于
     */
    public int compare(Object obj1, Object obj2);
}

(2)实现Comparator接口的类

public class BookNameComparator implements Comparator1 {
    @Override
    public int compare(Object obj1, Object obj2) {
        Book book1 = (Book)obj1;
        Book book2 = (Book)obj2;
        return book1.getBookName().compareTo(book2.getBookName());
    }
}

public class BookPriceNameComparator implements Comparator1 {
    @Override
    public int compare(Object obj1, Object obj2) {
        Book book1 = (Book)obj1;
        Book book2 = (Book)obj2;
        if(book1.getPrice() > book2.getPrice()){
            return -1;
        }else if(book1.getPrice()< book2.getPrice()){
            return 1;
        }else{
            return book1.getBookName().compareTo(book2.getBookName());
        }
    }
}

如果某个外部比较器只使用一次或者很少的次数,就可以不提供专门的类,而是使用匿名内部类。

(3)使用匿名内部类实现外部比较器

public class Test {
    public static void main(String[] args) {
        Comparable comp;
        Comparator comp2;
        Book book1
                = new Book("倚天屠龙记1","金庸1","清华大学出版社",35);
        Book book2
                = new Book("倚天屠龙记5","金庸5","清华大学出版社",35);
        int result = book1.compareTo(book2);
        System.out.println(result);


        Comparator1 cmp1 = new BookNameComparator();
        result = cmp1.compare(book1,book2);
        System.out.println(result);
        Comparator1 cmp2 = new BookPriceNameComparator();
        result = cmp2.compare(book1,book2);
        System.out.println(result);

         Comparator1 cmp3 = new Comparator1() {
            //代码块,每次创建对象的时候执行,并且早于构造方法执行
            {
                System.out.println("--匿名内部类通过代码块完成初始化操作---");
            }
            @Override
            public int compare(Object obj1, Object obj2) {
                Book book1 = (Book)obj1;
                Book book2 = (Book)obj2;
                return book1.getAuthor().compareTo(book2.getAuthor());
            }
        };
        result = cmp3.compare(book1,book2);
        System.out.println(result);
    }
}

结论:

  1. 匿名内部类可以实现一个接口,也可以继承一个类(可以是抽象类)。
  2. 匿名内部类只能实现一个接口,而不是多个
  3. 必须实现所有的方法,匿名内部类不能是抽象类
  4. 匿名内部类不可能有构造方法,因为类是匿名的
  5. 匿名内部类没有访问修饰符
  6. 如果想实现构造方法的一些初始化功能,可以通过代码块实现
  7. 如果要访问所在方法的局部变量,该变量需要使用final修饰。(JDK1.8可省略final)

 内部类的作用和使用场合

内部类的作用

  1. 内部类提供了更小的封装。只能让外部类直接访问,不允许同一个包中的其他类直接访问。
  2. 内部类可以直接访问外部类的私有属性,内部类被当成其外部类的成员。 但外部类不能访问内部类的内部属性。
  3. 接口只是解决了多重继承的部分问题,而内部类使得多重继承的解决方案变得更加完整。
  4. 用匿名内部类实现回调功能。我们用通俗讲解就是说在Java中,通常就是编写一个接口,然后你来实现这个接口,然后把这个接口的一个对象作以参数的形式传到另一个程序方法中, 然后通过接口调用你的方法,匿名内部类就可以很好的展现了这一种回调功能

内部类的使用场合:

  1. 由于内部类提供了更好的封装特性,并且可以很方便的访问外部类的属性。所以,在只为外部类提供服务的情况下可以优先考虑使用内部类。
  2. 使用内部类间接实现多继承:每个内部类都能独立地继承一个类或者实现某些接口,所以无论外部类是否已经继承了某个类或者实现了某些接口,对于内部类没有任何影响。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值