一、内部类简介
Java语言中允许在一个类(或方法、代码块)的内部定义另一个类,后者称为“内部类”(Inner Classes),也称为“嵌套类”(Nested Classes),封装它的类称为“外部类”。内部类与外部类之间存在 逻辑上的隶属关系,内部类一般只用在封装它的外部类或代码块中使用。
内部类优点:内部类技术使程序结构变得紧凑
内部类缺点:在一定程度上破坏了Java面向对象思想。
(1)内部类的作用
封装。将不想公开的实现细节封装到一个内部类中,内部类可以声明为私有的,只能在所在外 部类中访问。
提供命名空间。静态内部类和外部类能够提供有别于包的命名空间。
便于访问外部类成员。内部类能够很方便访问所在外部类的成员,包括私有成员也能访问。
(2)内部类的分类
图解:
二、成员内部类
定义:成员内部类类似于外部类的成员变量,在外边类的内部,且方法体和代码块之外定义的内部类。
(1)实例成员内部类
特点:实例内部类与实例变量类似,可以声明为公有级别、私有级别、默认级别或保护级别,即4种访问级别都可以,而外部类只能声明为公有或默认级别。
代码如下:
//外部类 public class Outer { // 外部成员变量 private int x = 10; // 外部类方法 private void print(){ System.out.println("调用外部类方法。。。。。"); } // 测试调用内部类 public void test(){ Inner inner = new Inner(); inner.display(); } // 内部类 class Inner{ // 内部类成员变量 private int x = 5; // 内部类方法 void display(){ // 访问外部类的成员变量x System.out.println("外部成员变量x = "+Outer.this.x); // 访问内部类成员变量x System.out.println("内部成员变量x = "+this.x); System.out.println("内部成员变量x = "+x); // 调用外部类的成员方法 Outer.this.print(); print(); } } }
测试代码:
public class HelloWorld { public static void main(String[] args) { // 通过外部类调用外部类 Outer outer = new Outer(); outer.test(); System.out.println("直接访问内部类"); // 直接访问内部类 Outer.Inner inner = outer.new Inner(); inner.display(); } }
总结:在内部类中this是引用当前内部类对象,若要引用外部类成员变量需要使用“外部类名.this”,如果内部类和外部类它们的成员命名没有冲突情况下,在引 用外部类成员方法时可以不用加“外部类名.this”。
内部类的类型表示“外部类.内 部类”,实例化过程是先实例化外部类,再实例化内部类,outer对象是外部类实例,outer.new Inner()表 达式实例化内部类对象。
(2)静态成员内部类
静态成员内部类与静态变量类似,在声明的时候使用关键字static修饰,静态成员内部类只能访问外部类静态成员。
代码如下:
//外部类 public class View { // 外部类实例变量 private int x = 20; // 外部类静态变量 private static int staticX = 10; // 静态成员内部类 static class Button{ // 内部方法 void onClick(){ // 访问外部类的静态成员 System.out.println(staticX); // 不能访问外部累的非静态成员 // System.out.println(x); } } }
测试代码:
public class HelloWorld { public static void main(String[] args) { // 直接访问内部类 View.Button button = new View.Button(); button.onClick(); } }
从代码View.Button button = new View.Button()可见,在声明静态内部时采用“内部类.静态内部类”形 式,实例化也是如此形式。
三、局部内部类
局部内部类就是在方法体或代码块中定义的内部类,局部内部类的作用域仅限于方法体或代码块中。局部内部类访问级别只能是默认的,不能是公有的、私有的和保护的访问级别,即不能使用public、 private和protected修饰。局部内部类也不能是静态,即不能使用static修饰。局部内部类可以访问外部 类所有成员。
代码如下:
//外部类 public class Outer { // 外部类成员变量 private int value = 10; // 外部类方法 public void add(final int x,int y){ // 局部变量 int z = 100; // 自定义内部类 class Inner{ // 内部类方法 void display(){ int sum = x+z+value; System.out.println("sum = "+sum); } } // Inner inner = new Inner(); // inner.display(); // 声明匿名对象 new Inner().display(); } }
测试代码:
public class HelloWorld { public static void main(String[] args) { Outer outer = new Outer(); outer.add(10,15); } }
上述代码在add方法中定义了局部内部类,在内部类中访问了外部类成员变 量value、方法参数x和方法局部变量z,其中方法参数应该声明为final。
四、匿名内部类
匿名内部类也就是没有名字的内部类
正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写
但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口
为什么要使用匿名内部类:说白了,就是因为想偷懒,不想写太多代码。如果可以,程序员完全可以通过实现接口或者继承抽象类的方式来实现而不用创建匿名内部类。但是使用匿名内部类的优点是显而易见的,可以少些代码,而且代码更加简洁。
匿名内部类的定义的语法格式:
new 实现接口(){ //匿名内部类类体部分 }
new 父类构造器(实参列表){ //匿名内部类类体部分 }
因此这两种方式的定义分别对应两种方式,一种是接口,另一种是抽象类。
对于实现接口,由于接口是没有构造函数的,注意这里一定是空参数。
第二种是调用父类的构造器,注意此处可以是空参数,也可以传入参数。
如何使用匿名内部类,代码如下:
第一种情况:实现接口
public interface Product { public double getPrice(); public String getName(); }
上面代码定义一个接口,接口里面两个抽象方法
public class Anonymous { public void test(Product product){ System.out.println(product.getName()+"--------"+product.getPrice()); } public static void main(String [ ] args ){ Anonymous as= new Anonymous (); //方法参数是匿名类 as.test(new Product() { @Override //实现方法 public double getPrice() { return 1234; } @Override //实现方法 public String getName() { return "caizhengjie"; } }); } }
注意:如果匿名内部类在方法中定义,它所访问的参数需要声明为final的。