第一类:定义在外部类局部位置上,分为局部内部类( 有 类名)、匿名内部类(没有类名)。
第二类:定义在外部类的成员位置上,分为成员内部类(没有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{
@Override
public void eat() {
System.out.println("学生韩梅梅正在吃饭");
}
}
Student student = new Student();
student.eat();
class Teacher implements behavior{
@Override
public 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() {
@Override
public void eat() {
System.out.println("学生韩梅梅正在吃饭");
}
};
student.eat();
Behavior teacher = new Behavior() {
@Override
public 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() {
@Override
public 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("张三"){
@Override
public 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() {
@Override
void 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() {
@Override
public 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() {
@Override
public void dance() {
System.out.println("你们都是黑子,只有我才是真爱粉");
}
});
ikun.show(new Peopel() {
@Override
public 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.成员)去访问。
这些都不重要就不演示了。