有名内部类
接口:
public interface Mammal {
public abstract void move();
}
有名内部类:
public class Body {
//有名内部类
class Heart{
public void work() {//有名内部类的方法
System.out.println("正在跳动......");
}
}
//静态代码块,创建对象时执行
{
Heart heart = new Heart();
heart.work();
//在非静态代码块中默认在new前有个 “this.”,故不用再加 “body.”
}
public static void main(String[] args) {
Body body = new Body();//创建对象
Heart heart = body.new Heart();//创建有名内部类对象,需要加 “主类的对象.”
heart.work();//通过有名内部类对象调用其work方法
}
}
结果:
正在跳动......
正在跳动......
匿名内部类
匿名内部类:必须和创建对象一起存在
创建方法:
new 父类构造器([参数列表])|接口(){
匿名内部类类体;
}
注:匿名内部类创建的对象一定是普通类或抽象类的子类对象,或接口的实现类
接口:
public interface Mammal {
public void move();
}
匿名接口内部类:
public class Body {
//匿名内部类由于没有名字,所以定义匿名内部类的同时要创建对象
int age = 2;//就如同这一样,必须把2赋值给一个变量,而不能单独写一个2
static Mammal mammal = new Mammal() {//匿名内部类,Mammal接口的实现类,static是为了能在下面主函数中直接调用这个内部类
@Override
public void move() {//重写接口的抽象方法
System.out.println("靠鳍游动......");
}
public void eat() {//新定义的方法
System.out.println("正在吃......");
}
};
public static void main(String[] args) {
mammal.move();//调用匿名内部类的move方法
/*匿名内部类常用于重写父类或者接口中的方法,当然也可以定义新的属性和方法,但此方法上转型对象无法调用
例如:
mammal.eat();不能这样直接用上转型对象mammal调用eat方法*/
//可以通过下面方式来调用eat方法,但此时重写的move方法就无效了,没有必要这样用
new Mammal() {//匿名内部类
@Override
public void move() {
System.out.println("靠鳍游动......");
}
public void eat() {
System.out.println("正在吃......");
}
}.eat();//直接调用eat方法
}
}
结果:
靠鳍游动......
正在吃......
匿名普通的内部类:
public class Test2 {
//匿名内部类由于没有名字,所以定义匿名内部类的同时要创建对象
int age = 2;//就如同这一样,必须把2赋值给一个变量,而不能单独写一个2
Object object = new Object() {//以Object为父类创建内部类
public void move() {
System.out.println("......");
}
};
public static void main(String[] args) {
//非上转型对象可以调用子类新增的属性和方法,但此时没有必要这么麻烦,且只能调用一个
new Object() {
public void move() {
System.out.println("......");
}
}.move();
}
}
匿名内部类对象:匿名内部类是普通类的子类;是接口的实现类
类体通常用于实现抽象方法或重写父类方法,但也可以定义自己新增的属性和变量
Object为父类,new Object()为子类,则object为上转型对象
匿名内部类中新增的属性和方法,无法在上转型对象中使用
内部类中使用外部变量
public class Test3 {
public void test(){
int age = 12;//局部变量
class Printer{
public void print(){
System.out.println(age);//在内部类中使用了内部类外的变量
}
}//内部类
}
}
内部类中可以直接使用外部变量(内部类必须在外部变量作用范围内)
如果内部类中使用了局部变量,则JDK8以前的版本中必须在局部变量前加final修饰
特殊的匿名内部类:函数式接口以及Lambda表达式
函数式接口:
仅有一个抽象方法的接口可以使用@FunctionalInterface注解修饰,这样的接口称之为函数式接口。
接口:
@FunctionalInterface
public interface IComputer {//函数式接口
int add(int a,int b);
}
由该接口创建内部类:
public class Test4 {
public static void main(String[] args) {
//按常规方法创建匿名内部类
IComputer computer = new IComputer() {
@Override
public int add(int a,int b) {
return a+b;
}
};
//Lambda方法创建:主要用于简化匿名内部类(JDK8以及以上)
IComputer computer =(int a,int b)->{
return a+b;
};
//也可以忽略不写参数的数据类型
IComputer computer =(a,b)->{
return a+b;
};
//如果方法体仅仅是一行返回值,则大括号和return可省略(同时省略)
IComputer computer =(a,b)-> a+b;
//输出结果
int result = computer.add(1, 1);
System.out.println(result);
}
}
内部类的访问权限
1、外部类或者外部接口的访问权限必须是public或者默认的
2、内部类或者内部接口则四种访问权限都可以
3、局部内部类不允许添加任何访问控制符
public class Test {//外部类必须是public或者默认的
//内部类访问权限定义方法像成员变量一样直接定义在内部类前
private int age;
private class Herat{
}
public static void main(String[] args) {
//局部内部类的定义和局部变量一样,都不允许添加访问控制符
int age;
class Body{
}
}
}
内部类的class文件
普通类:
package venus;
public class Mammal {
}
内部类:
package venus;
public class Body {
class A{//有名内部类
}
Mammal mammal = new Mammal() {//匿名内部类
};
Object object = new Object() {//匿名内部类
};
public static void main(String[] args) {
}
}
则在eclipse-workspace\venus\bin文件夹中生成了class文件如下:
其中Mamma l.class和Body.class为两个类的class文件
Body$A.class为Body类中有名内部类的class文件
Body$1.class和Body$2.class为Body类中的匿名内部类的class文件
总结:
有名内部类编译后生成“外部类 $ 内部类 . class”文件
匿名内部类编译后生成“外部类 $ 数字 . class”文件