什么是内部类?
顾名思义,在类A中定义了一个类B,那么类B就是内部类。
内部类的访问特点:
1.内部类可以直接访问外部类的成员,包括私有。
2.外部类要访问内部类的成员,必须创建对象。
成员内部类
成员内部类不用static修饰,如果使用,则为静态内部类
成员内部类中的成员变量可以用static修饰(JDK16及以上)
如何创建成员内部类的对象
直接创建格式:
外部类名.内部类名 对象名 = 外部类对象.内部类对象
public class Outer { //外部类Outer
String name;
class Inner{ //内部类Inner
}
}
public static void main(String[] args) {
Outer.Inner n =new Outer().new Inner();
}
new Outer ()可理解为外部类的对象,是一个调用者,调用内部类Inner的对象,然后将对象的地址值赋值给对象n
private修饰内部类
如果内部类使用private修饰,上述方法将会报错,因为被private修饰的方法只能在本类使用
private class Inner{ //private修饰内部类Inner
}
被private修饰的方法只能在本类使用,既然如此,我们可以在本类的外部类中定义一个方法 “getInstance” ,将其返回值定义成内部类对象,那么我们在其他类中调用此方法就可以间接定义内部类的对象。
public class Outer { //外部类Outer
String name;
private class Inner{ //private修饰内部类Inner
}
public Inner getInstance(){
return new Inner();
}
}
public static void main(String[] args) {
Outer o =new Outer();
o.getInstance();
}
内部类方法如何调用外部类成员变量?
内部类方法调用内部类成员变量的格式为 “ this.变量 ”,
内部类方法调用外部类成员变量的格式为 “外部类名.this.变量”
public class Outer { //外部类
int a=10;
class Inner{ //内部类
int a=20;
public void show() //本方法
{
int a=30;
System.out.println(Outer.this.a);
System.out.println(this.a);
System.out.println(a);
}
}
}
public class Inner_test {
public static void main(String[] args) {
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
总结
静态内部类
静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的需要创建外部类的对象。
如何调用静态类中的静态方法?
外部类名.内部类名.方法名();
Outer.Inner.show();
如何调用静态类中的非静态方法?
先创建对象,对对象调用
Outer.Inner oi = new Outer.Inner();
oi.show();
运行
public class Outer { //外部类
static class Inner{ //内部类
public static void show() //定义静态方法
{
int a=30;
System.out.println(a);
}
public void show2() //定义非静态方法
{
int a=30;
System.out.println("20");
}
}
}
public class Inner_test {
public static void main(String[] args) {
Outer.Inner.show(); //调用静态方法
Outer.Inner S1 = new Outer.Inner();
S1.show2(); //调用非静态方法
}
}
匿名内部类
匿名内部类格式
new 类名\接口名(){
重写方法;
};
Swim是一个接口类,其中有方法swim
public interface Swim {
public void swim();
}
以下是一个以Swim接口为基础的匿名内部类
new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
};
我们可以将括号里的这部分看做是一个没有名字的类
{
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
};
而 new Swim+这个没有名字的类则可以理解为创建了一个此匿名类的对象
new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
};
既然创建了此类的对象就自然可以对其自己的方法进行调用,“ .swim ”
new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
}.swim();
定义的匿名内部类new后如果是一个接口,就为实现关系,如果是一个类,就为继承关系
new Swim(){ //Swim为接口,实现关系
@Override
public void swim() {
}
};
new Animal(){ //Animal为类,继承关系
@Override
public void eat() {
}
};
总结
如果我们需要用到一个方法,且这个方法只使用一次,由于这个方法存在抽象类父类中,如果想要调用此方法就需要重新创建一个子类来继承父类,对此方法进行重写,然后创建一个子类的对象对此方法进行调用。但我们只使用这个方法一次,却要创建一个类来实现,这样显然很笨比很不划算。
于是我们可以使用匿名内部类,直接在new后写父类/接口的名字,匿名内部类是一个对象,而这个对象是以括号内的内容创建出来的。
在大括号的无名类内对父类/接口的抽象方法进行重写,然后采用下图这种格式直接.swim调用,省去了重新定义一个类的麻烦,它的本质是一个 带具体实现的父类或者接口的、匿名的子类对象。
new Swim(){
@Override
public void swim() {
System.out.println("重写后的游泳方法");
}
}.swim();