Java学习23--内部类

内部类

内部类就是在一个class里面定义另一个class,比如在A class 中定义一个 B class,那么B class相对于A class来说就称为内部类,而A类相对于B类就是外部类了。

为什么需要用内部类?
在一个class内部在定义另一个class可以隐藏细节和内部结构,封装性更好,让程序的结构更加合理。
内部类的分类:

1.成员内部类(非静态内部类)
2.静态内部类
3.局部内部类
4.匿名内部类

知识补充:

IDEA新建一个new object的快捷键

alt+回车两次

举例想要写语句 method1 x= new method1();

那么先手写new 类名()比如
new method1()

然后在这一行用ALT+回车两次
就快速出来method1 x= new method1();语句了

1.成员内部类(非静态内部类)

在一个class里定义另一个class。

举例 生成一个Outer class文件,在其中创建private int my_id,同时构建my_out method和Inner class(内部class)
然后在Inner class内部类里层在构建一个my_in method和getID method 其中getID method可以输出private int my_id

在主调用程序application中 把所有刚刚建立的method全部输出一遍。

提示!!! 在Java中,当内部类是非静态的(即没有static修饰符),它必须依赖于外部类的一个实例(也就是下面的x)才能被创建。这意味着,在创建内部类的实例之前,必须先创建一个外部类的实例。


package oop.Demo10;

public class Outer {
    private int my_id=8;
    public void my_out(){
        System.out.println("这是外部类的方法");
    }
    public class Inner{
        public void my_in(){
            System.out.println("这是内部的方法");
        }
        //getID获得外部类的私有属性
        public void getID(){
            System.out.println(my_id);
        }
    }
}



package oop;
import oop.Demo10.Outer;
public class Application {
    public static void main(String[] args) {
	
        Outer x = new Outer();
	      x.my_out();
        // 利用生成的object去生成new inner object
        // 先写x.new Inner();
        // 然后用快捷键alt+enter(twice)生成下面的y
		
        Outer.Inner y = x.new Inner();
        y.my_in(); //调用my_in method
        y.getID(); //获得外部类

    }

}


运行结果

这是外部类的方法
这是内部的方法
8

2.静态内部类

静态内部类(加了static修饰符)的构造不需要依赖于外部类对象,类中的静态组件都不需要依赖于任何对象,可以直接通过class create object,就如同创建普通实例 (比如下面的例子用的就是Outer.Inner y = new Outer.Inner(); 注意如果主程序和Inner class写在一个文件里,连Outer.都不用写)。

举例

package Class;

public class Test {
        //成员变量
        private String outer_name;
        //成员方法
        public void display(){
            System.out.println("这是外部类方法!");
            System.out.println(outer_name);
        }
        //静态内部类
        public static class InnerClass{
            private String inner_name;
            public InnerClass() {
                inner_name = "Inner Class";
            }

            //成员方法
            public void display(){
                System.out.println("这是静态内部类方法!");
                System.out.println(inner_name);
            }
        }

        // 主方法
        public static void main(String[] args) {
            Test x = new Test();
            x.display();
            // InnerClass是静态内部类,所以制造object y可以直接调用。
            // 构造不依赖与外部类,可以直接通过类本身进行构造!
            InnerClass y = new InnerClass();
            y.display();
        }
}


运行结果

这是外部类方法!
null
这是静态内部类方法!
Inner Class

思考 当Inner class标记为static时,为什么会有报错?

package oop.Demo10;

public class Outer {
    private int my_id=8;
    public void my_out(){
        System.out.println("这是外部类的方法");
    }
    public static class Inner{
        public void my_in(){
            System.out.println("这是内部的方法");
        }
        //getID获得外部类的私有属性
        public void getID(){
            System.out.println(my_id);//注意 这里的my_id报错了,因为static部分需要先加载,而此时自定义的my_id系统还不识别,所以报错
        }
    }
}

思考 一个java class文件可以含有多个class块,可以同时有多个标记为public的class块吗?答案:只能有一个 public class,其他都是一般的class块,否则报错

package oop.Demo10;

import org.w3c.dom.ls.LSOutput;

public class Outer {
    private int my_id=8;
    public void my_out(){
        System.out.println("这是外部类的方法");
    }
    public class Inner{
        public void my_in(){
            System.out.println("这是内部的方法");
        }
        //getID获得外部类的私有属性
        public void getID(){
            System.out.println(my_id);
        }
    }
}

public class A{//这里报错了,删掉public就正确了
    int a =12;
}

  1. 局部内部类
    在一个classA 里面的methodA里定义一个classB,classB的适用范围仅限method内部

下面是内部类InnerClass在一个方法体Test.display()中定义的示例。

package Class;
public class Test{
        //成员变量
        private String OuterName;
        //成员方法
        public void display(){
		//  class InnerClass就是局部内部类
            class InnerClass {
                public void print(){
                    System.out.println("666这是一个局部内部类方法!");
                }
            }
            InnerClass y = new InnerClass();
            y.print();
        }

        // 主方法
        public static void main(String[] args) {
            Test x = new Test();
            //x为Test类的object
            //执行x.display时发现需要先建立y,然后执行y.print
            //最终获得print结果“666这是一个局部内部类方法!”
            x.display();
        }

}


结果:

666这是一个局部内部类方法!

Process finished with exit code 0

4.匿名内部类Anonymous Class

适用前提:必须是用在子类或者含有单一method的接口

格式:new 类名/接口名(){
重写抽象方法
};

匿名内部类:没有名字的内部类。Anonymous classes are inner classes with no name。Anonymous class内部不可以写static members,但是可以有costant members。只有两种使用范围:接口或者子类。Implement an interface(而且里面只有一个method) 或者 extends a fatherclass

使用举例:构建匿名内部子类,子类重写父类的方法

package Class;
public class Test{
    public static void main(String[] args) {
        //这句new Animal(){XXX};仅仅相当于创建了Animal的匿名子类对象
        //如果没有写.eat();那么就是创建object完毕并,没有调用这个子类的对象,是不会有任何输出结果的
        new Animal(){
            //子类重写父类的方法eat
            public void eat(){
                System.out.println("dog is eating");
            }
        }.eat();


    }
}

Animal class内容

package Class;

public class Animal {
    public void eat(){
        System.out.println("animal is eating");
    };
}


输出结果:

dog is eating

Process finished with exit code 0

使用举例:匿名内部类+接口使用

在调用包含接口类型参数的method时,为了简化代码,可以直接通过匿名内部类的形式传入一个接口类型的参数,在匿名内部类中直接完成方法的实现。

package Class;

public class Test{
    public static void main(String[] args) {
       //下面的my_fun(XXX);是一步执行动作,执行的是后面定义的my_fun method,给了一个匿名内部类的object作为输入参数
        my_fun(
       new my_intef(){
            @Override
            public void run() {
                System.out.println("666 i jump, you jump!");
            }
        }
        );
    }

    //my_fun method的输入要求一个大的程序块my_intef接口的实现类对象
     static void my_fun(my_intef i) {
        i.run();
    }
 interface my_intef{
    //这里定义了一个interface名叫my_intef
//内部只有一个method名叫run,符合匿名内部类的创造条件
        public void run();
    }
}

输出结果:


666 i jump, you jump!

Process finished with exit code 0

举例,因为不能直接创建接口interface的object (同时常规连接interface的步骤比较繁复,需要通过class继承接口,然后class内部详细完成接口里的method),我们可以通过创建interface接口的匿名内部子类class,然后创建这个子类的object来间接快速连接到接口。

package Class;

public class Test{
    public static void main(String[] args) {
	
	//下面这段new my_intef程序块就是快速创建了一个一个匿名内部类的对象,
	//完成了连接接口class需要执行完毕的method go
	//注意new my_intef不需要强制起个名字比如x或y(当然 也可以赋值给另一个variable),而是直接程序块书写完毕,然后程序块整体调用【.go()】;
	//如果没有	【.go();】这一句,程序块书写完毕最后一个}后面是加分号的,因为这是完成一个内部类的具体书写同时新建了这个匿名内部类的object,这里注意理解
	
	 final String def_name = "Mike";
	 //这里的final也可以不写,但是final关键字是会被系统默热加上的
	 //所以这个def_name无法被再次赋值了
	 
        new my_intef(){
            @Override
            public void go() {
                System.out.println(def_name+" said: i jump, you jump!");
            }
        }.go(); 

    }


//这里定义了一个interface名叫my_intef
//内部只有一个method名叫go,符合匿名内部类的创造条件
    interface my_intef{
        public void go();
    }
}

Mike said: i jump, you jump!

Process finished with exit code 0


思考:
以前讲过interface本身不能用来new object,同时它本体没有权限构造method。下面的例子为什么能直接new interface class类型的object?
回答:
这里并不是直接new了interface类型的object。而是新建了interface类的(匿名内部)子类的object。
这里使用了匿名内部类的创建技巧,对于这种只有单一method的接口,可以快速构建出来了一个没有名字的连接interface的子类class的object,并没有直接用interface创建object。
注意看语句的最后,}加一个分号;表示用这个(匿名内部)子类的模板建立了一个object。
然后将这个object给到了父类UserService的引用变量y。
这就是常说的,java的多态:父类的引用指向子类。



package oop.Demo10;

public class Test {
    public static void main(String[] args) {

       
        //创建了连接UserService接口的匿名子类class,并在其中完成了hello method的具体实现
       
		//整体结构new UserService(){XXX};相当于新建了UserService的匿名子类对象
		//父类型的引用UserService y接收了UserService的匿名子类对象new UserService(){XXX};
		 //父类的引用指向子类
        UserService y= new UserService(){

            @Override
            public void hello() {
                System.out.println("output hello");

            }
        };//这里有一个分号,证明这是新建了匿名内部class的object。
        y.hello();
    }
}


//建立了一个接口叫做UserService,里面的hello menthod需要后来对接的class去实现
//接口类
interface UserService{
    void hello();

}


输出结果


output hello

  • 10
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值