一、内部类
Java 语言允许在一个类内部定义一个类(接口,枚举或注解),这种类称为内部类(inner class)或嵌套类(nested class)
使用内部类的目的增强两个类之间的联系,并可以使程序代码清晰、简洁。
使用内部类的优点:对只在一处使用的类进行分组;提高封装性;增强代码的可读性和可维护性。
Java的内部类可以分为:成员内部类、局部内部类、匿名内部类和静态内部类
1、成员内部类
成员内部类是没有用 static 修饰且定义在外层类的类体中。
内部类编译后将单独生成一个类文件。
代码示例:
package com.itcast.innerClass;
//学习内部类
//成员内部类
public class OuterClass {
private int x = 200;
//内部类
public class InnerClass{
int y = 300;
public int calculate() {
//可以访问外层的成员变量x
return x+y;
}
}
private void makeInner() {
//创建内部类对象
InnerClass ic = new InnerClass();
System.out.println(ic.calculate());
}
public static void main(String[] args) {
// OuterClass outer = new OuterClass();
//也可以使用这种方法
OuterClass.InnerClass inner = new OuterClass().new InnerClass();
//在外层类的外面要创建内部类的实例先必须创建一个外层类的对象,因为内部类对象对外层类对象有一个隐含的引用
// OuterClass.InnerClass inner = outer.new InnerClass();
System.out.println(inner.calculate());
//在使用成员内部类时需要注意下面几个问题
//成员内部类中不能定义static变量和方法
//成员内部类也可以使用abstract和final修饰,其含义与其它类一样
//成员内部类还可以使用private、public、protected或包可访问修饰符
}
}
2、局部内部类
可以在方法体或语句块内定义类。在方法体或语句块(包括方法、构造方法、局部块、初始化块或静态初始化块)内部定义的类称为局部内部变量(local inner class)。
局部内部类不能视做外部类的成员,只对局部块有效,同局部变量一样,在说明它的块之外完全不能访问,因此也不能有任何访问修饰符。
代码示例
package com.itcast.innerClass;
//局部内部类
public class OuterClass2 {
private String x= "hello";
public void makeInner(int param) {
final String y = "local variable";
//局部内部类
class InnerClass {
public void seeOuter() {
System.out.println("x = "+x);
System.out.println("y = "+y);
System.out.println("param = "+param);
}
}
//调用内部类的方法
new InnerClass().seeOuter();
}
public static void main(String[] args) {
OuterClass2 oc = new OuterClass2();
oc.makeInner(47);
}
}
使用局部内部类时要注意下面问题:
(1)局部内部类同方法局部变量一样,不能使用 private 、public 、protected 等访问修饰符,也不能用 static 修饰,但可以使用 final 或 abstact 修饰。
(2)局部内部类可以访问外层类的成员,若要访问其所在方法的参数和局部变量,这些参数不能修改。
(3)static 方法中定义的局部内部类,可以访问外层类中定义的 static 成员,不能访问外层类的实例成员。
3、匿名内部类
定义类最终目的是创建一个类的实例,但如果某个类的实例只使用一次,可以将类的定义和实例的创建在一起完成,或者说在类定义的同时就创建一个实例。以这种方式定义的没有名字的类称为匿名内部类(anonymous inner class)。
声明和构建内部类的一般格式如下:
new TypeName(){
/*此处为实体类*/
}
匿名内部类可以继承一个类或者实现一个接口,这里 TypeName 是匿名内部类所继承的类或实现的接口。如果该实现一个接口,该类是 Object 类的直接子类。匿名类继承一个类或实现一个接口不需要使用 extends 或 implements 关键字。匿名内部类不能同时继承一个类和实现一个接口,也不能实现多接口。
因为内部类没有名称,所以类体中不能定义构造方法。又因不知道类名,所以只能在定义类的同时用 new 关键字创建类的实例。实际上,匿名类的定义、创建对象发生在同一个地方。
另外,上式是一个表达式,它返回一个对象的引用,所以可以直接使用或将其赋给一个引用变量。
代码示例:
继承定义匿名内部类:
package com.itcast.innerClass;
//继承类定义匿名内部类
class Animal{
public void eat() {
System.out.println("I like eat anthing.");
}
}
public class AnimalTest {
public static void main(String[] args) {
Animal dog = new Animal() {//继承Animal类,重写eat类
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("I like eat bones.");
}
}; //这里分号是赋值语句的结束
dog.eat();
}
}
实现接口定义匿名类:
package com.itcast.innerClass;
//实现接口定义匿名内部类
interface Printable{
public abstract void print(String message);
}
public class PrintableTest {
public static void main(String[] args) {
Printable printer = new Printable() {
@Override
public void print(String message) {
System.out.println(message);
}
};
printer.print("这是惠普打印机");
}
}
4、静态内部类
与类的其它成员类似,静态内部类使用 static 修饰,静态内部类特称嵌套类(nested calss),例如:
public class OuterClass{
//成员变量或者方法
static class InnerClass{
//成员变量或方法
}
}
InnerClass是静态内部类。静态内部类与成员内部类的行为完全不同,下面是他们的不同之处:
- 静态内部类中可以定义静态成员,而成员内部类不能;
- 静态内部类只能访问外层类的静态成员,成员内部类可以访问外层类的实例成员和静态成员;
- 创建静态内部类的实例不需要先创建一个外层类的实例;相反,创建成员内部类实例,必须先创建一个外层类的实例。
代码示例:
package com.itcast.innerClass;
//静态内部类
public class MyOuter {
private static int x = 100;
//静态内部类
public static class MyInner{
private String y = "hello";
public void innerMethod() {
System.out.println("x is " + x); //可以访问外层类的静态成员x
System.out.println("y is " + y);
}
}
public static void main(String[] args) {
//不需要外层类的实例就可以直接创建一个静态内部类实例
MyOuter.MyInner snc = new MyOuter.MyInner();
snc.innerMethod();
}
}
静态内部类实际上是一种外部类,它不存在对外部类的引用,不通过外部类的实例就可以创建一个对象。程序中静态内部类的完整名称为 MyOuter.MyInner ,此时必须使用完整的类名(如 MyOuter.MyInner)创建对象。因此,有时将静态内部类称为顶层类。
静态内部类不具有任何对外层实例的引用,因此静态内部类中的方法不能使用 this 关键字访问外层类的实例成员,然而这些方法可以访问外层类的static成员。这一点与一般类的 static 方法的规则相同。
在类的内部还可以定义内部接口,内部接口的隐含属性是 static 的,当然也可以指定。嵌套的类或者接口可以有任何访问修饰,入 public、protected、private 。在内部类中还可以定义下一层的内部类,形成类的多层嵌套。
代码示例:
package com.itcast.innerClass;
public class MyOuter2 {
String s1 = "Hello";
static String s2 = "World";
//内部接口的声明
interface MyInterface{
void show();
}
static class MyInner2 implements MyInterface{
@Override
public void show() {
System.out.println("s1 = "+new MyOuter2().s1);
System.out.println("S2 = "+ s2); //可以访问外部类的static变量
}
}
public static void main(String[] args) {
MyOuter2.MyInner2 inner2 = new MyOuter2.MyInner2();
inner2.show();
}
}