什么是内部类?
为什么要学习内部类?
可以发现,发动机虽然跟汽车相关,但发动机不像车龄或颜色一样,只用一个变量就可以描述,而是要有发动机品牌,发动机年限,多个变量描述发动机。那么这样写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() {//对外提供Inner
return 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是类,这里是继承关系
@Override
void eat() {
// TODO Auto-generated method stub
System.out.println("重写eat");
}
};
}
}
进一步了解什么是匿名内部类
实际上,红圈内的内容才是匿名内部类,因为它是没有名字的。
而蓝圈在做的是是创建一个匿名内部类
为什么要学习匿名内部类?
class Animal{
void shout() {}
}
class Dog extends Animal{
@Override
void shout() {
// TODO Auto-generated method stub
System.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();//还可以这样去调用方法
}
}