java中的内部类主要分为两类四种:
第一类:定义在外部类局部位置上,分为局部内部类( 有 类名)、匿名内部类(没有类名)。
第二类:定义在外部类的成员位置上,分为成员内部类(没有static修饰)、静态内部类(使用static修饰)。
一:局部内部类
局部内部类是定义在外部类的局部位置,比如方法中,并且有类名。
局部内部类的使用
1.局部内部类可以直接访问外部类的所有成员,包含私有的,访问方式——直接访问。
2.不能添加访问修饰符,因为它的地位就是一个局部变量,局部变量是不能使用修饰符的。但是可以使用final修饰,因为局部变量也可以使用final。
3.作用域仅仅在定义它的方法或代码块中
4.外部类访问局部内部类,访问方式:创建对象,在访问(注意:必须在作用域内)
对上面的使用以代码的形式呈现:
public class TestDemo {public static void main(String[] args) {Person person = new Person();person.method2();}
}
class Person{//外部类private String name = "张三";private int age = 20;private void method1(){System.out.println("外部类中的method1方法");}public void method2(){final class Student{//局部内部类可以加fianl关键字private String name = "王五";public void method3(){method1();//可以访问外部类中的成员}}/*** 外部类访问局部内部类的方式:创建对象再访问*/Student student = new Student();student.method3();}
}
5.外部其他类不能直接访问局部内部类(因为局部内部类是一个局部变量)
6.如果外部类和局部内部类的成员重名时,默认遵循就近访问原则,如果打破原则访问外部类成员,则可以使用(外部类名.this.成员)去访问。
代码演示上面两个使用:
public class TestDemo {public static void main(String[] args) {Person person = new Person();person.method2();//不能直接访问局部内部类//person.student;//报错:Cannot resolve symbol 'student'}
}
class Person{//外部类private String name = "张三";private int age = 20;private void method1(){System.out.println("外部类中的method1方法");}public void method2(){final class Student{//局部内部类可以加fianl关键字private String name = "王五";public void method3(){System.out.println(name);//遵循就近原则System.out.println(Person.this.name);//同名时访问外部成员method1();//可以访问外部类中的成员}}/*** 外部类访问局部内部类的方式:创建对象再访问*/Student student = new Student();student.method3();}
}
二:匿名内部类
上面四种内部类中只需要掌握这一种即可,这是以后代码中经常会用到的,很重要。
匿名内部类的定义
匿名内部类是没有名称的内部类。在Java中调用某个方法时,如果该方法的参数是接口类型,除了可以传接口实现类外,还可以使用实现接口的匿名内部类作为参数,在匿名内部类中直接完成方法的实现。
通过一段代码来解释匿名内部类:
public class TestDemo02 {public static void main(String[] args) {People people = new People();people.method();}
}
class People{private String name;public void method(){class Student implements behavior{@Overridepublic void eat() {System.out.println("学生韩梅梅正在吃饭");}}Student student = new Student();student.eat();class Teacher implements behavior{@Overridepublic void eat() {System.out.println("老师李华正在吃饭");}}Teacher teacher = new Teacher();teacher.eat();}
}
interface behavior{public void eat();
}
从上面可以看到People类里面有两个内部类Student、Teacher,两个类都实现了behavior接口并实现了里面吃这个行为。
细心的朋友已经观察到了,上面的代码不是局部内部类吗,和匿名内部类与啥关系。在这里我们通过局部内部类主要是为了引出匿名内部类。观察上面的代码,发现为了调用内部类里面的方法,就必须实例化对象,然后在调用。如果内部类一多,比如现在有Father、Marther.......众多的内部类,难道都要一个个实例吗,为了简化开发,java开发者就创建了匿名内部类,看下面的代码。
public class TestDemo02 {public static void main(String[] args) {People people = new People();people.method();}
}
class People{private String name;public void method(){Behavior student = new Behavior() {@Overridepublic void eat() {System.out.println("学生韩梅梅正在吃饭");}};student.eat();Behavior teacher = new Behavior() {@Overridepublic void eat() {System.out.println("老师李华正在吃饭");}};teacher.eat();}
}
interface Behavior{public void eat();
}
上面的代码就是利用匿名内部类实现多对象的创建,合理使用匿名内部类可以很大程度简化代码量。
为看懂上面的代码,现在作如下分析:
1.分析上面student的编译类型和运行类型,编译类型为Behavior,运行类型正是匿名内部类。可能有的人会很以为,这个匿名内部类在哪里,怎么没看见。所谓匿名内部类,就是没有名字的类,也不能说没有名字吧,jdk底层给这个类分配了一个名字,就叫做People$1,只不过不显示出来,看如下代码就知道了:
public class TestDemo02 {public static void main(String[] args) {People people = new People();people.method();}
}
class People{private String name;public void method(){Behavior student = new Behavior() {@Overridepublic void eat() {System.out.println("学生韩梅梅正在吃饭");}};student.eat();System.out.println(student.getClass());//获取全路径类名}
}
interface Behavior{public void eat();
}
2.jdk底层创建完匿名内部类以后马上就实力化了该类的对象,也就是说底层一共做了两步动作,第一是创建匿名内部类,第二步是实力化对象。
3.上面的匿名内部类的操作步骤和局部内部类是一样的,只不过简化了代码而已。
匿名内部类的语法
new 接口或类(参数列表){类体;
};
下面在演示其他两种不同的匿名内部类:
一:基于类的匿名内部类
public class TestDemo02 {public static void main(String[] args) {new People("张三").method();}
}
class People{private String name;public People(String name) {this.name = name;}public void method(){Father father = new Father("张三"){@Overridepublic void sleep() {System.out.println("匿名内部类中的sleep方法");}};father.sleep();}
}
class Father{private String name;public Father(String name){this.name = name;}public void sleep(){System.out.println("正在睡觉");}
}
上面的匿名内部类是继承至Father这个类的,当匿名内部类调用sleep方法的时候,根据继承机制他首先在本类中找,刚好本类中有一个sleep方法,他就会执行本类中的方法,结果如下:
这里需要重点提一下:有得朋友可能会想,既然匿名内部类也是一个类,那么在类里面写一些方法,然后实力化调用这些方法是不是也行。这里需要指出,匿名内部类里面确实可以写自己的方法,但是不能调用,因为根据继承机制(实现接口也相当于继承,因为接口是一种特殊的类),匿名内部类作为一个子类,他是无法调用自身特有的方法的。这里也不能强转,因为你根本就不知道匿名内部类的运行类型是啥。所以综上,匿名内部类里面只能重写父类中的方法,然后调用。
二:基于抽象类的匿名内部类
public class TestDemo02 {public static void main(String[] args) {People people = new People();people.method();}
}
class People{private String name;public void method(){Animal dog = new Animal() {@Overridevoid eat() {System.out.println("小狗吃东西");}};dog.eat();}
}
abstract class Animal{abstract void eat();
}
匿名内部类的使用
1.匿名内部类既是一个类,又是一个对象,既有定义类的特征,又有创建对象的特征。所以可以调用匿名内部类中的方法。
匿名内部类的使用和局部内部类一样,除了第四条。
匿名内部类的使用场景
一:当做实参直接传递
public class TestDemo02 {public static void main(String[] args) {show(new Peopel() {@Overridepublic void dance() {System.out.println("全名制作人们大家好,我是练习时长两年半的个人练习生蔡徐坤");}});}public static void show(Peopel peopel){peopel.dance();}
}
interface Peopel{public void dance();
}
二:在多态中的应用
public class TestDemo02 {public static void main(String[] args) {Ikun ikun = new Ikun();ikun.show(new Peopel() {@Overridepublic void dance() {System.out.println("你们都是黑子,只有我才是真爱粉");}});ikun.show(new Peopel() {@Overridepublic void dance() {System.out.println("会唱、跳、rap的才是ikun");}});}
}
class Ikun{public void show(Peopel peopel){peopel.dance();//这里会发生动态绑定}
}
interface Peopel{public void dance();
}
三:成员内部类
成员内部类的概念
成员内部类是定义在外部类的成员位置上,并且没有static修饰
成员内部类的使用
1.可以直接访问外部类的所有成员,包括私有的。外部类访问成员内部类访问方式:创建对象,再访问;
2.可以添加任意访问修饰符,因为它的地位就是一个成员;
3.作用域和外部类的其他成员一样,为整个类体
4.如果外部类和内部类的成员重名时,内部类访问的话,遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
5.外部其他类访问成员内部类有三种方式:第一种实例化外部类,然后访问;第二种将内部类作为外部类的成员实例化然后访问;第三种在外部类里面编写一个方法,可以返回内部类对象。
下面用代码演示上面的使用:
public class TestDemo02 {public static void main(String[] args) {People people = new People();people.method();//访问的第一种方式实例化外部类,通过外部类里面的方法访问//People.Student student = people.new Student();//访问的第二种方式,将内部类作为外部类的成员实例化然后访问/*** 访问的第三种方式* People.Student getStudent = people.getStudent();* getStudent.say();*/}
}
class People{//外部类private String name = "张三";private int age = 20;private void hi(){System.out.println("打招呼");}public class Student{//内部类private String name = "李四";private int age = 21;public void say(){System.out.println("name="+name+" age="+People.this.age);}}//返回Student类public Student getStudent(){return new Student();}public void method(){//外部类访问内部类Student student = new Student();student.say();}
}
四:静态内部类
静态内部类的概念
静态内部类是定义在外部类的成员位置上,并且有static修饰
静态内部类的使用
1.可以直接访问外部内的所有静态成员,包含私有的,但不能直接访问非静态的成员
2.可以添加任意访问修饰符,因为它的地位就是一个成员;
3.作用域和外部类的其他成员一样,为整个类体
4.如果外部类和内部类的成员重名时,内部类访问的话,遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问。
这些都不重要就不演示了。