内部类
1.什么是内部类
内部类是指在一个外部类内定义的类。
2.内部类的分类
内部类可分为有名内部类和匿名内部类。其中,有名内部类按照是否有static修饰分为静态内部类和非静态内部类。
3.内部类的位置
package human;
public class Body {
int age;
String sex;
/*
* 直接定义在外部类中的内部类
*/
class Heart {
void beat() {
System.out.println("心脏跳动");
}
}
/*
* 定义在代码块中的内部类
*/
{
class Leg{ //静态内部类
void walking() {
System.out.println("腿迈动");
}
}
Leg leg = new Leg();
leg.walking();
}
/*
* 定义在方法中的内部类
*/
public void Look(){
class Eye{
public void see() {
System.out.println("眼睛在看");
}
}
Eye eye = new Eye();
eye.see();
}
}
Test类:
package human;
import human.Body.Heart;
public class Test {
public static void main(String[] args) {
Body body = new Body();
Heart heart = body.new Heart();
heart.beat();
body.Look();
}
}
Test类运行结果
其中,直接定义在外部类中的内部类可以由public、protected、默认的和private四种访问权限修饰(普通外部类、接口和抽象类只能使用public和default修饰),也可以使用static修饰( static不能修饰普通外部类、接口和抽象类);
但是定义在方法或代码块中的内部类不能有访问修饰符修饰,也不能有static修饰。
注意:
在非外部类中定义的内部类和局部变量一样,其使用范围从定义的位置开始到其所在直接语句块结束。
public class OutClass {
public static void main(String[] args) {
if(args!=null) {
class InClass{
}
}
InClass inClass = new InClass();//无法创建对象,因为内部类作用范围无法作用到这里
}
}
4.有名内部类
1.静态内部类
定义:有名内部类中,没有static修饰的为非静态内部类。
- 静态内部类只能直接定义在外部类中
如下代码将会提示错误:
public class OutClass {
public static void main(String[] args) {
/**
* 静态有名内部类
*/
static class InClass {
public void printInfo() {
System.out.println("我是有名内部类");
}
}
}
}
提示表明该类的位置非法
- 静态内部类仅能直接访问外部类的静态成员变量和方法,可以通过创建外部类的对象间接使用非静态的成员变量和方法。
- 只有有名静态内部类中才允许有静态成员(静态属性、静态代码块和静态方法)。
2.非静态内部类
非静态内部类可以调用静态和非静态成员变量,可以调用静态和非静态方法
5.匿名内部类
定义:匿名内部类就是一个没有显式的名字的内部类。
-
匿名内部类由于没有类名而不能单独存在,定义匿名内部类的=同时须直接实例化该类,其语法格式如下:
new 父类构造器 ( [参数列表 ] ) | 接口 ( ) {
//匿名内部类类体
}
1. 接口匿名内部类
创建接口类:IMammal0:
public interface IMammal0 {
void move();
}
创建Ocean类,用于测试
public class Ocean {
public static void main(String[] args) {
IMammal0 mammal0 = new IMammal0() {//接口匿名内部类,是接口的实现类
@Override
public void move() {
System.out.println("接口实现类的游泳");
}
};
mammal0.move();
}
}
运行,控制台输出:
2.抽象类匿名内部类
创建抽象类:IMammal1:
public abstract class Mammal1 {
abstract void move();
}
测试类Ocean类:
public class Ocean {
public static void main(String[] args) {
Mammal1 mammal1 = new Mammal1() { //抽象类的子类
@Override
void move() {
System.out.println("抽象类的子类游动");
}
};
mammal1.move();
}
}
运行,控制台输出:
3.普通类的子类
创建I普通类IMammal2:
public class Mammal2 {
void move() {
}
}
测试类Ocean类:
public class Ocean {
public static void main(String[] args) {
Mammal2 mammal2 = new Mammal2() {//普通类的子类
@Override
void move() {
System.out.println("普通类的子类游动");
}
};
mammal2.move();
}
}
运行,控制台输出:
4.特点
- 匿名内部类一定是接口的实现类(该实现类仅能实现一个接口)或类(普通类或抽象类)的子类,其中new 关键字后面的类名或接口名即是该匿名内部类继承的父类或实现的接口;(上述第3点)
- 匿名内部类没有名字,构造方法要求方法名和类名相同,所以匿名内部类不能自定义构造方法,但是可以通过非静态代码块初始化成员变量;
public class Test {
class car{
int age;
{
age = 10;
}
}
}
-
匿名内部类一定不能是抽象类;
抽象类是只声明方法的存在而不去具体实现它的类。抽象类不能被实例化,也就是不能创建其对象。而匿名内部类在定义时直接实例化该类。
-
可以在匿名内部类中添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用(上转型对象不能调用新增属性和方法),只能被非上转型对象方式创建的匿名内部类对象所调用,例如:
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()、重写的方法或继承的方法,也无法调用继承的属性
上转型对象无法调用新增的breath方法
}
}
interface IMammal {
void move();
}
代码2:
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();
}
6.Lambda表达式
- Java支持Lambda 表达式始于Java 8,它的出现简化了函数式接口匿名内部类的语法,其表达式语法如下:
([参数1], [参数2], [参数3],… [参数n])->{代码块}
先定义一个函数式接口:
package lambda;
@FunctionalInterface
public interface Calculate {
void add(int a,int b);
}
- 使用一般的内部类形式:
package lambda;
public class Computer {
public static void main(String[] args) {
Calculate calculate = new Calculate() {
public void add(int a, int b) {
System.out.println("结果是:"+(a+b));
}
};
calculate.add(2, 3);
}
}
运行,控制台输出为:
- 使用Lambda表达式:
package lambda;
public class Computer {
public static void main(String[] args) {
Calculate calculate = (int a, int b) -> {
System.out.println("结果是:"+(a+b));
};
calculate.add(3, 3);
}
}
运行,控制台输出
- 另一种lambda表达式,省去变量类型声明:
package lambda;
public class Computer {
public static void main(String[] args) {
Calculate calculate = (a, b) -> {
System.out.println("结果是:"+(a+b));
};
calculate.add(1, 3);
}
}
运行,控制台输出
- 如果方法没有返回值且只有一行代码,则Lambda表达式语法可以是这种形式:([参数1], [参数2], [参数3],… [参数n])->单行语句
package lambda;
public class Computer {
public static void main(String[] args) {
Calculate calculate = (a, b)->System.out.println("结果是:"+(a+b));
calculate.add(1, 7);
}
}
运行,控制台输出: