什么是内部类?
为什么要学习内部类?
可以发现,发动机虽然跟汽车相关,但发动机不像车龄或颜色一样,只用一个变量就可以描述,而是要有发动机品牌,发动机年限,多个变量描述发动机。那么这样写Car类是不合适的
所以要用上内部类描述发动机
内部类的访问特点
1.内部类可以直接访问外部类,包括私有
2.外部类要访问内部类,必须创建对象
这里的this指针用法要复习一下,
如果Car.this没写,this.carName直接写成carName也是没错的,因为就算不写编译器也会自动添加this关键字。这个过程被称为隐式引用。
内部类的分类
成员内部类
举个例子
可以看到,我们把内部类理解当成成员属性就好了。
1.成员内部类的修饰符
着重介绍一个,private修饰成员内部类,怎么理解呢?
把他当成成员变量一样就好了。即只能在类内(Car类里)访问,只能在外部类内实例化对象(比如说第二个红框的位置),外部类以外是操作不到的
那如果用static修饰成员内部类呢?实际上这就叫静态内部类了,后面会介绍
2.获取成员内部类的对象
实例化方法1:
class Outer{class Inner{;}}public class Main {public static void main(String[] args) {Outer o = new Outer();Outer.Inner io1 = o.new Inner();//可以简写成这样Outer.Inner io2 = new Outer().new Inner();}
}
实例化方法2:
如果成员内部类是私有的,外部就访问不到了,就不能用方法1来实例化对象
要怎么改呢?写一个对外提供内部类的方法
class Outer{private class Inner{;}public Inner getInner() {//对外提供Innerreturn new Inner();}}
如何接收呢?
这样是错的
下面是对的
或者直接使用也可以。此处打印的是地址
静态内部类
1)注意:静态内部类只能访问外部类中的静态变量和静态方法,如果想要访问非静态的,需要创建对象。
2)创建静态内部类的格式:外部类名.内部类名 对象名 = new 外部类名.内部类名()。因为是静态的,所以就不用先创建一个外部类对象,再创建内部类。
如何调用静态内部类中的方法?
3)调用非静态方法的格式:先创建内部类的对象,用对象调用
4)调用静态方法的格式:外部类名.内部类名.方法名()
只要是静态的东西,都可以用类名点直接获取!
对于(1)
class Outer{int a = 10;static int b = 20;static class Inner{public void show1() {System.out.println(new Outer().a);//此时是报错的,因为不能直接访问非静态的变量System.out.println(b);//但是b可以,因为b是静态的}static public void show2() {System.out.println(new Outer().a);System.out.println(b);}}}public class Main {public static void main(String[] args){Outer o = new Outer();Outer.Inner io = new Outer.Inner();io.show1();Outer.Inner.show2();}}
局部内部类
1)将内部类定义在方法里就叫局部内部类,类似与方法里的局部变量
2)外界是无法直接使用的,要在方法内部创建并调用。
3)该类可以直接访问外部类的成员,也可以访问方法内的局部变量
class Outer{int a = 10;void show() {int b = 20;class Inner{//注意!把局部内部类当成局部变量就行了!//public等修饰符不能修饰局部变量,那么也不能修饰局部内部类public void test1() {System.out.println(a);System.out.println(b);}}Inner i = new Inner();i.test1();}}public class Main {public static void main(String[] args){Outer o = new Outer();o.show();}}
匿名内部类
怎么写匿名内部类?
interface Swim{public void swim();
}abstract class Animal{abstract void eat();
}public class Solve {public static void main(String[] args) {//编写匿名内部类代码new Swim(){//Swim是接口,这里是实现关系public void swim() {System.out.println("重写swim");}};new Animal() {//Animal是类,这里是继承关系@Overridevoid eat() {// TODO Auto-generated method stubSystem.out.println("重写eat");}};}}
进一步了解什么是匿名内部类
实际上,红圈内的内容才是匿名内部类,因为它是没有名字的。
而蓝圈在做的是是创建一个匿名内部类
为什么要学习匿名内部类?
class Animal{void shout() {}
}
class Dog extends Animal{@Overridevoid shout() {// TODO Auto-generated method stubSystem.out.println("dog is barking");}}public class Main {public static void method(Animal a) {//多态a.shout();}public static void main(String[] args){//假设我们现在要调用method函数实现dog的行为,该怎么办呢?//以前的方法://创建一个狗的类,实例化一个狗的类,类内重写方法Dog d = new Dog();method(d);//以前的方法有点麻烦,因为如果我们只需要使用一次dog,那么单独再写一个Dog类就太麻烦了//所以可以用匿名内部类,用完一次就丢。//跟以前的办法相比,这个只要重写并创建匿名对象就行了method(new Animal(){void shout() {System.out.println("dog2 is barking");}});}
}
匿名内部类的一些实用小技巧
1.创建的对象可以被接收
class Animal{void shout() {}
}public class Main {public static void method(Animal a) {//多态a.shout();}public static void main(String[] args){//我们知道,new Animal()其实是创建对象的过程,只不过是匿名的//那么我们可不可以用一个对象来接收呢?可以!//那这样有什么好处呢?//这样我们就不用单独再写一个Dog类,省去了不必要的类,//而且调用比上一段代码更灵活(个人感觉)Animal a = new Animal(){//注意,因为经过重写,所以实际上是创建了一个子类的对象//但这里用父类的对象接收,所以这里也是多态!void shout() {System.out.println("dog is barking");}};method(a);method(a);method(a);//...//想用几次就用几次,代码比上一段简洁一些}
}
2.直接调用方法
public class Main {public static void main(String[] args){ new Animal(){void shout() {System.out.println("dog is barking");}}.shout();//还可以这样去调用方法}
}