内部类的概念
定义:在一个类内部进行其他类结构的嵌套操作。
//外部类Outer
class Outer{
private String outStr ="外部类中的字符串";
//定义一个内部类
class Inner{
private String inStr= "内部类中的字符串";
//定义一个普通方法
public void print(){
//调用外部类的str属性
System.out.println(outStr);
}
}
//外部类通过创建内部类的对象间接访问内部类元素
//在外部类中定义一个方法,该方法负责产生内部类对象并调用print()方法
public void func(){
//内部类对象
Inner in = new Inner();
//内部类对象提供的print
in.print();
}
}
//运行结果:打印外部类中的字符串
public class Test{
public static void main(String[] args)
{
//创建外部类对象
Outer out = new Outer();
//外部类方法
out.func();
}
}
内部类的优点
- 内部类中的属性和方法,其他类都不能访问内部类,即使是外部类也不能直接访问,而内部类拥有外部类所有元素的访问权限。
- 内部类可以使类继承多个具体类或抽象类。
- 编写简易。
内部类与外部类的关系
- 外部类可以通过内部类的引用间接访问内部类元素(要想访问内部类属性,必须先创建内部类对象)。
- 对于非静态的内部类,内部类的创建依赖外部类的实例对象,在没有外部类实例之前是无法创建内部类的。
- 内部类可以直接访问外部类的元素(包括私有域),外部类在内部类之前创建,创建内部类时会将外部类的对象传入。
- 内部类是一个相对独立的个体,与外部类没有关系。
内部类的创建
在外部类外部创建非静态内部类
Outer.Inner in = new Outer().new Inner();
在外部类外部创建静态内部类
Outer.Inner in = new Outer.Inner();
在外部类内部创建内部类
Inner in = new Inner();
内部类的分类
成员内部类
- 成员内部类作为外部类的一个成员存在,与外部类的属性、方法并列,可以无限制的访问外部类的所有成员。但是外部类要访问内部类的成员属性和方法则要通过内部类实例来访问。
- 成员内部类是依附外部类的,只有创建了外部类才能创建内部类。
- 成员内部类不能存在任何static的静态变量和方法;
class Outer {
private String name = "test";
public static int age =20;
public void outerDisplay(){
System.out.println("outerClass");
}
//定义成员内部类
class Inner{
//public static int num =10;
public void innerDisplay()
{
//使用外部类的属性
System.out.println(name);
System.out.println(age);
//使用外部类的方法
outerDisplay();
}
}
//推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时
public Inner getInnerClass(){
return new InnerClass();
}
}
public class Test{
public static void main(String [] args){
Outer outer = new Outer();
Outer.Inner inner = outer.getInnerClass();
inner.innerDisplay();
}
}
静态内部类
- 静态内部类定义在类中、 任何方法外,用static修饰,在静态内部类中可以定义静态或者非静态的成员,但是不可以访问外部类的非static成员变量和方法,而内部类则都可以。
- 静态内部类的创建不依赖外部类,可以直接创建,而不需要通过生成外部类对象来生成。
- 静态内部类与非静态内部类之间的区别:非静态内部类在编译完成之后会隐含地保存一个指向创建它的外部类引用,但是静态内部类没有。
public class Outer {
private String sex;
public static String name = "zsy";
//静态内部类
static class Inner1{
//在静态内部类中可以存在静态成员
public static String _name1 = "zsy_static";
public void display(){
//静态内部类只能访问外部类的静态成员变量和方法,外部类里的其他非静态成员变量和方法不能访问
System.out.println("OutClass name :" + name);
}
}
//非静态内部类
class Inner2{
//非静态内部类中不能存在静态成员
public String _name2 = "zsy_inner";
//非静态内部类中可以调用外部类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + name);
}
}
//外部类方法
public void display(){
//外部类访问静态内部类需要加上:内部类.
System.out.println(Inner1._name1);
//静态内部类可以直接创建实例不需要依赖于外部类
new Inner1().display();
//非静态内部的创建需要依赖于外部类
Outer.Inner2 inner2 = new Outer().new Inner2();
//访问非静态内部类的成员需要使用非静态内部类的实例
System.out.println(inner2._name2);
inner2.display();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.display();
}
}
方法内部类
- 方法内部类不允许使用访问权限修饰符。
- 方法内部类对外部完全隐藏,除了创建这个类的方法可以访问它以外,其他方法和类均不能访问。
- 方法内部类如果要使用方法形参,该形参必须使用final声明(JDK8形参变为隐式final声明)。
class Outer{
private int num = 5;
//普通方法
public void dispaly(int temp)
{
//方法内部类即嵌套在方法里面
class Inner{
public void func()
{
System.out.println(num);
temp++;
System.out.println(temp);
}
}
//方法内部类在方法里面创建
new Inner().func();
}
}
public class Test{
public static void main(String[] args)
{
Outer out = new Outer();
out.dispaly(2);
}
}
局部内部类
- 局部内部类是在方法中或者作用域中定义的内部类,与成员内部类基本一致,只是作用域不同。
- 与局部变量相似,在局部内部类前面不能使用private、protected、public等访问修饰说明符修饰,也不能使用static修饰,但可以使用final和abstract修饰。
- 局部内部类中不可定义static静态变量。
- 局部内部类可以访问外部类的局部变量(方法内的变量),但是变量必须是final。
- 要想使用局部内部类时,需要生成对象,对象调用方法,在方法中才能调用局部内部类。
//定义在作用域中:
public class Outer{
private void func(boolean b){
if(b){
//定义局部内部类
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("zsy");
String string = ts.getSlip();
}
}
public void track(){
func(true);
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.track();
}
}
匿名内部类
- 如果某个类的实例只是用一次,则可以将类的定义与类的创建放到一起完成。以这种方法定义的类称为匿名内部类。
- 匿名内部类没有名字,没有访问修饰符,没有显式定义构造方法(唯一一种无构造方法类),但是会调用父类构造方法,可以访问外部类的所有成员。
- 匿名内部类所在方法的形参需要被匿名内部类使用时,这个形参必须是final。
- 匿名内部类中不能存在任何静态变量和方法;
- 匿名内部类必须继承一个抽象类或者实现一个接口,一般隐式的继承某一个父类或者实现某一个接口,不需要使用extends和implements关键字。但不能同时继承类和实现接口。
- 匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
//匿名内部类
//声明一个接口
interface MyInterface {
//接口中方法没有方法体
void test();
}
class Outer{
private int num = 5;
public void dispaly(int temp)
{
//匿名内部类,匿名的实现了MyInterface接口
//隐藏的class声明
new MyInterface()
{
public void test()
{
System.out.println("匿名实现MyInterface接口");
System.out.println(temp);
}
}.test();
}
}
public class Test{
public static void main(String[] args)
{
Outer out = new Outer();
out.dispaly(2);
}
}