1.什么是内部类
- 在一个外部类中定义的类称为内部类
- 内部类可以直接在类中定义,也可以在方法中和代码块中定义;但是需要注意的是:syso代码块中或方法中才能用
- 按照是否有类名分为有名内部类和匿名内部类
2.有名内部类
- 说明:全局有名内部类的使用方式类似于全局变量;局部有名内部类的使用方式类似局部变量——它们都有固定的使用范围
Body类:
package com.jd;
/**
* 外部类
*/
public class Body {
/**
* 有名内部类
*/
public class Heart{
public void beat(){
System.out.println("正在跳动...");
}
}
}
Test类:
package com.jd;
import com.jd.Body.Heart;
public class Test {
public static void main(String[] args) {
Body body = new Body();
Heart heart = body.new Heart();
heart.beat();
}
}
3.匿名内部类
- 匿名内部类:匿名内部类没有类名,但是创建对象需要类名,所以匿名内部类在定义的时候要和创建对象一起定义
Object object = new Object() {
};
需要注意的是,匿名内部类后要有一个分号
- 匿名内部类的语法:
new 父类构造器([参数列表])|接口(){
匿名内部类类体
};
- 匿名内部类的特点:
1.普通类匿名内部类实质为普通类的子类
普通类:
class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Sea {
Mammal whale = new Mammal() {//调用Mammal中的无参构造方法
@Override
public void move() {
System.out.println("鲸鱼靠鳍移动......");
}
};
}
2.匿名内部类是抽象类的子类
抽象类:
abstract class Mammal {
public Mammal(String name) {
System.out.println(name);
}
abstract void move();
}
public class Sea {
Mammal mammal = new Mammal("鲸鱼") {// 调用Mammal中的有参构造方法
@Override
void move() {
System.out.println("鲸鱼靠鳍移动......");
}
};
}
3.匿名内部类是接口的实现类
接口:
interface Mammal {
abstract void move();
}
public class Sea {
Mammal mammal = new Mammal() {
@Override
public void move() {
System.out.println("鲸鱼靠鳍移动......");
}
};
}
需要注意的是,匿名内部类此时必须实现完接口中的所有抽象方法,若没有实现完,则此时的匿名内部类为一个抽象类,这时必须有一个子类完全实现其抽象方法;但是,匿名内部类没有类名,所以没有子类;此时也证明了匿名内部类不能是抽象类。
4.匿名内部类不能自定义构造方法,但是可以通过非静态代码块初始化成员变量;
5.可以在匿名内部类中添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用,只能被非上转型对象方式创建的匿名内部类对象所调用
代码1:
public class Test {
public static void main(String[] args) {
IMammal whale = new IMammal() {
public void breath() {
System.out.println("鲸鱼正在呼吸......");
}
@Override
public void move() {
System.out.println("鲸鱼靠鳍游动......");
}
};//此时匿名内部类对象为上转型对象
whale.breath();// 上转型对象无法调用新增的breath方法
}
}
interface IMammal {
void move();
}
public class Test {
public static void main(String[] args) {
new IMammal() {
public void breath() {
System.out.println("鲸鱼正在呼吸......");
}
@Override
public void move() {
System.out.println("鲸鱼靠鳍游动......");
}
}.breath();// 调用新增的breath方法
}
}
interface IMammal {
void move();
}
- 总结:无论是匿名内部类还是有名内部类,javac都会产生一个独立的class文件:编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+$+内部类类名;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字
4.内部类的其他需要掌握的方面
- 外部类或外部接口 public 默认的;但是直接在类中定义的内部类,可以有public ~private
package com.edu.zzu.test;
public class Body {
int age =12;
private class Heart {
void work() {
System.out.println("正在跳动");
}
}
- 如果在内部类中使用局部变量的值,则:JDK8.0及+可以不适用final修饰,8.0以前必须使用fianl
package com.edu.zzu.test;
public class Body {
public void eat(final String name) {
class Baby{
{
System.out.println(name);
}
}
}
}
需要注意的是,上述代码不能写到main方法里面,原因很简单,方法不能套方法;
private修饰的成员变量可以在内部类中使用
package com.edu.zzu.test;
public class Body {
private int age =12;
public class Heart {
void work() {
System.out.println("正在跳动"+age);
}
}
- 局部变量不能使用访问权限,访问权限用于限制成员变量或方法能否在另一个类中被使用,但因为局部变量已经限定,所以局部变量不能使用访问权限
package com.edu.zzu.test;
public class Body {
private int age =12;
//有名内部类
public class Heart {
private int number=13;
void work() {
System.out.println("正在跳动"+age);
}
}
此处有一个疑问,这时在内部类中的变量为局部变量,为什么这时候在局部变量的前面加上访问控制符,却并没有报错?