分类
- 定义:内部类是指在一个外部类内定义的类。
- 按照是否有类名分为有名内部类和匿名内部类。
有名内部类
Body类:
package com.jd;
/**
* 外部类
*/
public class Body {
/**
* 有名内部类
*/
//第一种形式:直接定义在外部类中
public class Heart{
public void beat(){
System.out.println("正在跳动...");
}
}
//第二种:定义在外部类的方法中
public static void main(String[] args) {
class Heart{
public void beat() {
System.out.println("正在跳动……");
}
}
Heart heart = new Heart();
heart.beat();
}
//第三种:在非静态代码块中
public void print(){
int a=0;
if(a==0) {
class Heart{
public void beat() {
System.out.println("正在跳动……");
}
}
Heart heart = new Heart();
heart.beat();
}
}
}
----------
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();
}
}
说明:
全局有名内部类的使用方式类似于全局变量;局部有名内部类的使用方式类似局部变量——它们都有固定的使用范围;
匿名内部类
- 匿名内部类由于没有类名而不能单独存在,定义匿名内部类的同时须直接实例化该类,其语法格式如下:
new 父类构造器([参数列表])|接口(){//注意是父类构造器
//匿名内部类类体
};//注意这个分号
package com.baidu.neibulei;
public class Animal {
public static void main(String[] args) {
//匿名内部类
Object object = new Object(){
void move() {
System.out.println("正在移动");
}
};//到此结束
}
}
普通类
普通类【匿名内部类】实质为【普通类的子类】
//普通类
class Mammal {
public void move() {
System.out.println("正在移动......");
}
}
public class Sea {
Mammal whale = new Mammal() {//调用Mammal中的无参构造方法
//Mammal类型的变量whale是父类
@Override
public void move() {//匿名内部类是子类,new Mammal()指定的对象是子类
System.out.println("鲸鱼靠鳍移动......");
}
};//从Mammal开始到分号结束就是一个上转型对象
//全局变量
public static void main(String[] args) {
Sea sea = new Sea();
sea.whale.move();//出现多态
//输出 鲸鱼靠鳍移动......
}
}
抽象类
抽象类【匿名内部类】实质为【抽象类的子类】。
//抽象类
abstract class Mammal {
//有参构造方法
public Mammal(String name) {
System.out.println(name);
}
//抽象方法
abstract void move();
}
public class Sea {
Mammal whale = new Mammal("鲸鱼") {// 调用Mammal中的有参构造方法
@Override
void move() {
System.out.println("鲸鱼靠鳍移动......");
}
};
public static void main(String[] args) {
Sea sea = new Sea();
sea.whale.move();//出现多态
}
}
接口
接口【匿名内部类】实质为【接口的实现类】。
//接口类
interface Mammal {
abstract void move();
}
public class Sea {
Mammal whale = new Mammal() {
@Override
public void move() {
System.out.println("鲸鱼靠鳍移动......");
}
};
public static void main(String[] args) {
Sea sea = new Sea();
sea.whale.move();//出现多态
}
}
匿名内部类特点
-
匿名内部类一定是接口的实现类(该实现类仅能实现一个接口)或类(普通类或抽象类)的子类,其中new 关键字后面的类名或接口名即是该匿名内部类继承的
父类或实现的接口
; -
匿名内部类不能自定义构造方法,但是可以通过非静态代码块初始化成员变量;
-
匿名内部类一定不能是抽象类;
-
可以在匿名内部类中添加新的属性和方法,但是这些属性和方法不能被上转型对象所调用,只能被非上转型对象方式创建的匿名内部类对象所调用,
package com.baidu.neibulei;
public class Test1 {
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方法,
whale.move();//可以调用原来的方法 鲸鱼靠鳍游动......
}
}
interface IMammal {
void move();
}
----------
public class Test1 {
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();
}
静态内部类
- 按照是否有
static
修饰分为静态内部类和非静态内部类,有static修饰的为静态内部类,没有static修饰的为非静态内部类。
静态有名内部类
//Body类:
package com.jd;
/**
* 外部类
*/
public class Body {
/**
* 静态有名内部类
*/
public static class Heart{
public void beat(){
System.out.println("正在跳动...");
}
}
public static void main(String[] args) {
Heart heart = new Heart();
//本类使用则无须使用外部类类名
heart.beat();
}
----------
//Test类:
package com.jd;
import com.jd.Body.Heart;//引包
public class Test {
public static void main(String[] args) {
Heart heart = new Body.Heart();
//跨类使用则须“外部类类名.内部类名”
heart.beat();
}
}
静态匿名内部类
class Father {
public void eat() {
System.out.println("筷子吃饭....");
}
}
/**
* 外部类
*/
public class OutClass {
/**
* 静态匿名内部类
*/
static Father son = new Father(){
@Override
public void eat() {
System.out.println("筷子吃饭....");
}
};
}
注意
- 如果为static内部类只能
直接
定义在外部类中。不能定义在方法等中。
public class OutClass {
public static void main(String[] args) {
/**
* 静态有名内部类
*/
static class InClass {
public void printInfo() {
System.out.println("我是有名内部类");
}
}
}
}
- 静态内部类仅能
直接
访问外部类的静态成员变量和方法,可以通过创建外部类的对象间接使用非静态的成员变量和方法。
public class OutClass {
private double weight=72;
public static void print(String name) {
System.out.println(name);
}
static class InClass{
{
double weight = new OutClass().weight;
//由于weight是非静态的,所以在静态内部类中使用时必须先创建外部类对象
print("Tom");//由于print方法为静态方法,所以可以直接使用。
}
}
}
- 在非外部类中定义的内部类和局部变量一样,其使用范围从定义的位置开始到其所在直接语句块结束。
public class OutClass {
public static void main(String[] args) {
if(args!=null) {
class InClass{
}
InClass inClass = new InClass();
}//到此结束
//InClass inClass = new InClass();//无法创建对象,因为内部类作用范围无法作用到这里
}
}
- 只有
有名
静态内部类中才允许有静态成员(静态属性、静态代码块和静态方法)。
特点
-
内部类是一个独立的类:编译之后内部类会被编译成独立的.class文件,如果该内部类为有名内部类,则有名内部类字节码文件名为
外部类的类名+$+内部类类名
;如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字
; -
普通外部类、抽象类和接口可以有内部类(匿名的或有名的);
-
内部类可以
直接
定义在类中,也可以定义在方法或代码块中;
1、其中直接定义在外部类中的内部类可以有public、protected、默认的和private四种访问权限修饰(普通外部类、接口和抽象类只能使用public和default修饰),也可以使用static修饰( static不能修饰普通外部类、接口和抽象类);
2、但是定义在方法或代码块中的内部类不能有访问修饰符修饰,也不能有static修饰,因为此时是局部内部类
的。
- 内部类可以访问外部类的所有访问权限的成员变量
public class OutClass {
private String name;
class InClass{
{
System.out.println(name);
}
}
}
-
在局部变量作用的范围内,如果定义的内部类需要使用该局部变量,则该变量必须有
final
修饰。 -
从 Java 8开始,如果定义的内部类需要使用该局部变量,则该变量可以不使用final修饰。
代码1
public class OutClass {
public void print(final String name) {//由于局部变量name要在InClass内部类中使用,所以需要加final;方法参数前面加final修饰表示只能在调用方法时为该参数指定值,不允许再在方法体中进行二次修改。
final int weight = 9;//由于局部变量weight要在InClass内部类中使用,所以需要加final;
class InClass{
public void print() {
System.out.println(name+","+weight);
}
}
new InClass().print();
}
public static void main(String[] args) {
new OutClass().print("Tom");
}
}
代码2
public class OutClass {
public static void main(String[] args) {
final int i = 8;//由于局部变量i要在InClass内部类中使用,所以需要加final;
class InClass {
public void print() {
System.out.println(i);
}
}
InClass inClass = new InClass();
inClass.print();
}
}
Lambda 表达式
- Java支持Lambda 表达式始于
Java 8
,它的出现简化了函数式接口匿名内部类的语法,其表达式语法如下:
([参数1], [参数2], [参数3],.... [参数n])->{代码块}
//那是一个减号
- 如果方法
没有返回值且只有一行代码
,则Lambda表达式语法可以是这种形式:([参数1], [参数2], [参数3],.... [参数n])->单行语句
//匿名内部类:
@FunctionalInterface
interface IMammal {
void move(String name);
}
public class Test {
public static void main(String[] args) {
IMammal whale = (name) -> {
System.out.println(name+"正在移动......");
};
whale.move("鲸鱼");
}
}
//Lambda 表达式:
@FunctionalInterface
interface IMammal {
void move(String name);
}
public class Test {
public static void main(String[] args) {
IMammal whale = (name) -> System.out.println(name+"正在移动......");
whale.move("鲸鱼");
}
}
- 如果方法
有返回值且只有一行代码
,则Lambda表达式语法可以是这种形式:([参数1], [参数2], [参数3],.... [参数n])->表达式