内部类
内部类就是在一个类的内部定义一个类,比如在A中定义了一个B类,那么B类相对于A类来说就称为内部类,而A相对于B类就是外部类
内部类不是在一个java源文件中编写两个平行的类,而是在一个类的内部再定义另一个类,我们把外边的类叫做外部类,在其内部编写的类叫做内部类
内部类分为四种
- 成员内部类
- 静态内部类
- 局部内部类
- 匿名内部类
成员内部类
成员内部类中不能写静态属性和方法
实例化内部类,首先需要实例化外部类,通过外部类去调用内部类
public class Outer{
private int id; //默认为0
public void out(){
Inner sir = new Inner(); //不需要显示的Outer标识符,它们是隐含存在的
System.out.println("这是外部类方法");
}
class Inner{
public int id;
public void in(){
//同名属性,显示调用 Outer.this
System.out.println("这是内部类方法" + Outer.this.id);
}
}
}
public class Test{
public static void main(String[] args){
//实例化成员内部类分两步
//1.实例化外部类
Outer outObject = new Outer();
//2.通过外部类调用内部类
Outer.Inner inObject = outObject.new Inner();
//测试,调用内部类中方法
inObject.in();//打印:这是内部类方法
}
}
成员内部类
- 成员内部类可以访问外部类的所有属性,(包括私有的成员变量和方法)
- 要想访问内部类中的内容,必须通过外部类对象来实例化内部类
- 能够访问外部类所有的属性和方法,原理就是通过外部类对象实例化内部类对象时,外部类对象把自己的引用传进了内部类,使内部类可以通过Outer.this去调用外部类的属性和方法
一般都是隐式调用了,但是当内部类中有属性或者方法名和外部类中的属性或方法名相同的时候,就需要通过显示调用Outer.this了
静态内部类
用static修饰的内部类就是静态内部类
public class Outer{
private int id; //默认为0
public void out(){
Inner sir = new Inner(); //静态的内部类不需要依赖外部类,所以不用this,
sir.id = 0;
System.out.println("这是外部类方法");
}
private static class Inner{
public int id;
public void in(){
System.out.println("这是内部类方法");
}
}
}
【注意】
-
内部类能调用外部类的方法和属性,在静态内部类中也行,因为静态内部类没有了指向外部类对象的引用。除非外部类中的方法或者属性也是静态的。在static关键字的用法有说。
-
静态内部类能够直接被外部类给实例化,不需要使用外部类对象
Outer.Inner inner = new Outer.Inner();
-
静态内部类中可以声明静态方法和静态变量,但是非静态内部类中不可以声明静态方法和静态变量
局部内部类
局部内部类是在一个方法内部声明的一个类
局部内部类中可以访问外部类的成员变量及方法
局部内部类中如果要访问该内部类所在方法中的局部变量,那么这个局部变量就必须是final修饰的
局部内部类一般作用和在成员内部类中说到的类似,有两个注意点:
-
在局部内部类中,如果要访问局部变量,哪么该局部变量要用final修饰
final修饰变量:变为常量,会在常量池中存放。
如果不使用final修饰,当局部内部类被实例化后,方法弹栈,局部变量随之消失,这个时候局部内部类对象去调用该局部变量时,就会报错,因为局部变量已经没了。
当局部变量用final修饰后,就会存放在常量池,就算方法弹栈,局部变量还在常量池中,局部内部类一样能够调用。
不适用final类修饰,编译会报错
public class Outer{ private int id; public void method(){ final int CID = 3;//局部变量cid 要让局部内部类使用,就得变味final并且赋值,不使用final就会报错 class Inner{ //外部类方法中定义的类 //局部内部类的第一个方法 public void in(){ System.out.println("这是局部内部类"); } //局部内部类中使用变量cid的方法 public void useCID(){ System.out.println(CID); } } } }
-
局部内部类不能通过外部类对象直接实例化,而是在方法中实例化出自己来,然后通过内部类对象调用自己类中的方法。
public class outer{ private int id; public void out(){ System.out.println("外部类方法"); } public void methodz(){ final int ID = 5; //必须定义为final否则报错 class Inner{ public void in(){ //使用到了局部变量 System.out.println("这是局部内部类" + ID); } } //关键:在method方法中自己创建内部类实例,然后调用内部类中的方法,等待外部类调用method方法,就可以执行到内部类中的方法了 //局部内部类只能在自己的方法中用,因为局部内部类相当于一个局部变量,出了方法就找不到了 Inner In = new Inner(); In.in(); } }
匿名内部类
在这四种内部类中,以后可能用到最多的是匿名内部类,所以说匿名内部类是最常见的一种内部类。
匿名对象就是,只要使用一次,那么我们就是需要new Object().method().就可以了。而不需要给这个实例保存到改类型的引用变量中去。这就是匿名对象
public class Test{
public static void main(Strig[] args){
Apple apple = new Apple();
apple.eat();
//将new出来的Apple实例赋给apple变量保存起来,但是我们只需要用一次,就可以这样写
//这种就叫做匿名对象的使用,不把实例保存到对应的引用变量中
new Apple().eat();
}
}
class Apple{
public void eat(){
System.out.println("我要被吃了");
}
}
匿名内部类和匿名对象是一个道理:
匿名对象:我只需要使用一次,那么我就不用声明一个该类型变量来保存对象了
匿名内部类:我也只需要使用一次,那我就不需要在类中先定义一个内部类,而是等待需要用的时候,我就在临时实现这个内部类,因为次数少,可能就这一次,那么这样写内部类,更方便。不然先写出一个内部类的全部实现来,然后就调用它一次,岂不是用完之后就一直放在哪,那没必要。
- 匿名内部类需要依托于其他类或者接口来创建
- 如果依托的是类,那么创建出来的匿名内部类就默认是这个类的子类
- 如果依托的是接口,那么创建出来的匿名内部类就默认是这个接口的实现类
- 匿名内部类的声明必须是使用new关键字的时候
- 匿名内部类的声明及创建对象必须一气呵成,并且之后不能重复使用,因为没有名字
A是一个类(普通类、抽象类都可以),依托于A类创建一个匿名内部类对象
main:
A a = new A(){
//实现A中的抽象方法
//或者重写A中的普通方法
};//这个大括号里面其实就是这个内部类的代码,只不过是声明该内部类的同时就是要new创建了其对象,并且不能反复使用,因为没有名字
B是一个接口,依托于B接口创建一个匿名内部类对象
B b = new B(){
//实现B中的抽象方法
};
- 匿名内部类除了依托的类或接口之外,不能指定继承或者实现其他类或接口,同时也不能被其他类所继承,因为没有名字
- 匿名内部类中,我们不能写出其构造器,因为没有名字
- 匿名内部类中,除了重写上面的方法,一般不会再写其他独有的方法,因为从外部不能直接调用到。(间接是调用到的)
【总结】
**new Test(){实现接口中方法的代码};**这个的作用就是将接口给实现了,只不过这里实现了的是该接口的匿名类,也就是说这个类没有名字。
只能使用这一次,我们知道了这是一个类,将其new出来,就能获得一个实现了Test接口的类的实例对象,通过该实例对象,就能调用该类中的方法了,因为其匿名类是在一个类中实现的
实现原理等后期自己去看源码