内部类

分类

  • 定义:内部类是指在一个外部类内定义的类
  • 按照是否有类名分为有名内部类匿名内部类

有名内部类

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])->表达式
    这里写图片描述
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值