什么是内部类?我们知道当我们去描述一个汽车时,我们会定义车的名字,车的年限,车的颜色,车的发动机年限,车的发动机的年龄。
public class Car{
String carName;
int carAge;
String carColor;
String engineName;
int engineAge;
}
但是我们发动机的年限和发动机的年限不属于车的属性,且单独存在没有意义。
这时,我们就可以用到内部类(内部类表示的事物是外部类的一部分,内部类单独出现没有任何意义)
public class Car{
String carName;
int carAge;
String carColor;
class Engine{ //成员内部类,与上面的成员变量地位一样
String engineName;
int engineAge;
}
}
内部类的访问特点:
①内部类可以直接访问外部类的成员,包括私有
②外部类要访问内部类的成员,必须创建对象
内部类分为:①成员内部类
②静态内部类
③局部内部类
④匿名内部类
①成员内部类:上面书写的第二张图片就是成员内部类的书写,成员内部类的地位和成员变量是一样的,所以它也同样能被public、protected、默认、private、static修饰,在JDK16之后,成员内部类中变量也可以被private修饰。
那么如何获取成员内部类对象?
1.在外部类中编写方法,对外提供内部类的对象(当内部类用private修饰时一般用这个)
2.直接创建格式:外部类名.内部类名 对象名=外部类对象.内部类对象;
public class Outer{
String name;
private class Inner{
}
public Inner getInstance(){ //在外部类中编写方法,对外提供内部类对象
return new Inner();
}
}
public class Test{
public static void main(String[] args){ //通过Outer类调用getInstance方法返回内部类的对象
Outer o=new Outer();
Object Inner=o.getInstance(); //因为Inner类没有手动添加继承,可以利用多态用
System.out.println(o.getInstance()); //最大的类Object接收
}
}
public class Outer{
private String name;
class Inner{
}
}
public class Test{
public static void main(String[] args){
Outer.Inner oi=new Outer().new Inner(); //由于测试类无法直接获取成员内部类的对象,需要
} //通过先创建外部类对象再通过访问内部类成员来
} //创建,因为成员方法的地位和成员内部类的地位
//是一样的
那我们如何在内部类中获得外部类中的变量呢?
public class Outer{
private int a=10;
class Inner{
private int a=20;
public void show(){
int a=30;
System.out.println(a); //30
System.out.println(this.a); //20
System.out.println(Outer.this.a); //10
}
}
}
②静态内部类:被static修饰的内部类(静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建对象)
注意事项:1.静态内部类也是成员内部类中的一种
2.静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类的对象
创建静态内部类对象的格式:外部类名.内部类名 对象名=new 外部类名.内部类名();
使用非静态方法的格式:先创建对象,用对象调用
调用静态方法的格式:外部类名.内部类名.方法名();
public class Car{ //外部类
String carName;
int carAge;
String carColor;
static class Engine{ //静态内部类
String engineName;
int engineAge;
}
}
public class Test{
public static void main(String[] args){ //静态的成员可以直接由类名调用
Car.Engine ce=new Car.Engine();
}
}
③局部内部类:1.将内部类定义在方法里面就叫做局部内部类,类似于方法里面的局部变量
2.外界是无法直接使用局部内部类,需要在方法内部创建对象并使用
3.该类可以直接访问外部类的成员,也可以访问方法内的局部变量
④匿名内部类:隐藏了名字的内部类,可以写在成员位置,也可以写在局部位置
格式: new 类名或者接口名(){
重写方法:
};
格式的细节:包含了继承或实现,方法重写,创建对象。
整体就是一个类的子类对象或者接口的实现类对象
使用场景:当方法的参数是接口或者类时,
以接口为例,可以传递这个接口的实现类对象,
如果实现类只要使用一次,就可以用匿名内部类简化代码。
public class Test{
public static void main(String[] args){
new Swim(){
@Override
public void swim(){
System.out.println("重写了游泳的方法");
}
};
new Animal(){ //利用匿名内部类继承了抽象类,所以要重写抽象类里所有的
@Override //抽象方法,匿名内部类的整体是一个对象
public void eat(){
System.out.println("重写了eat方法");
}
};
method(
new Animal(){ //创建一个继承于Animal的子类作为参数传给Animal父类
@Override
public void eat(){
System.out.println("狗吃骨头");
}
}
);
}
}
public static void method(Animal a){ //Animal a=子类对象,利用了多态
a.eat();
}
public abstract class Swim{
public abstract void swim();
}
public abstract class Animal{
public abstract void eat();
}
public class Test{
public static void main(String[] args){
//实现了接口的多态,因为s相当于通过Swim父类创建的对象,而右边相当于用匿名内部类创建的Swim
//的子类对象,也就相当于 父类类型 对象名称=new 子类对象;
Swim s=new Swim(){
@Override
public void swim(){
System.out.println("重写之后的方法");
}
};
s.swim(); //利用多态调用成员方法,遵守编译看左边,运行看右边
new Swim(){
@Override
public void swim(){
System.out.println("重写之后的方法");
}.swim(); //匿名内部类的整体是一个对象
}
}
}
public abstract class Swim(){
public abstract void swim("重写之前的游泳方法");
}