内部类概念
定义在另一个类内部的类
内部类主要特点:
内部类可以很好的实现隐藏,可以使用public(默认)、protect、private修饰符。以前声明类的时候都是public,或者不写。外部类不能使用protect、private修饰符。
内部类可以访问外部类所有的成员,包括私有的成员。
外部类不能访问内部类的成员和方法。必须建立内部类的对象才能访问。
内部类可以解决一些问题,比如间接的去实现多继承。
内部类可以避免修改接口,而实现同一个类中两种同名方法的调用。
内部类分类:
成员内部类
1、成员内部类属于外部类的实例成员,成员内部类可以有public、private、default、protected权限修饰符。在成员内部类中访问外部类的成员方法和属性,要使用“外部类名.this.成员方法”和“外部类名.this.成员属性”的形式。
2、创建成员内部类的实例使用“外部类名.内部类名 实例名=外部类实例名.new 内部类构造方法(参数)”的形式。
3、成员内部类不能与外部类重名。
4、不能再成员内部类中定义static属性、方法、类(static final形式的常量定义除外)。因为一个成员内部类的实例必然与一个外部类的实例相关联。static成员完全可以移到其外部类中去。
public class Main {
public static void main(String[] args) {
// OuterClass outerClass = new OuterClass();
// InnerClass innerClass = outerClass.new InnerClass();
Outer1 outer1 = new Outer1();
Outer1.Inner1 inner1 = outer1.new Inner1();
outer1.outerShow();
inner1.innerShow();
}
}
// 产生三个自己码文件 Main.class Outer1.class Outer1$Inner1.class
class Outer1 {
private String name = "zhangsan";
private int num1 = 10;
public void outerShow() {
System.out.println(name);
System.out.println(num1);
//外部类不能直接访问内部类的成员和方法
// System.out.println(num2);
//外部类要想访问内部类的属性和方法,必须先产生内部类对象
Inner1 inner1 = new Inner1();
inner1.innerShow();
}
//private class Inner1 私有的时候其他类不能创建内部类对象
public class Inner1 {// 是否对外公开
private String name = "lisi";
private int num2 = 20;
//静态的常量是可以的
private static final int num3 = 20;
// 在成员内部类中不能声明静态的成员,包括属性和方法
// private static int num3=30;
public void innerShow() {
System.out.println("----------");
System.out.println(name);
System.out.println(num2);
// 成员内部类可以直接访问外部类的属性和方法,包括私有的
System.out.println(num1);
outerShow();
//Outer1.this外部类对象的引用,没有同名方法可以不加
System.out.println(Outer1.this.name);
Outer1.this.outerShow();
}
}
}
//内部类可以避免修改接口,而实现同一个类中两种同名方法的调用。
//具体的实用意义不大,只是为了演示学习内部类
public class Main3 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Son son = new Son();
son.show();
son.show2();
}
}
abstract class Parent {
public abstract void show();
}
interface IShow {
public abstract void show();
}
// class Son extends Parent implements IShow{
//
// @Override
// public void show() {
// }
// }
class Son extends Parent {
@Override
public void show() {
System.out.println("抽象类中show");
}
private class Inner2 implements IShow {
@Override
public void show() {
System.out.println("Inner2中show");
}
}
public void show2() {
new Inner2().show();
}
}
静态内部类
1、使用static修饰的成员内部类叫静态内部类。
2、静态内部类和外部类没有任何关系,只是在生成类名和类定义的时候有影响。静态内部类可以看做是与外部类平级的类。使用方式与外部类平级的类完全相同。
3、创建静态内部类的实例:外部类名.内部类名 实例名 = new 外部类名.内部类名(参数);
4、静态内部类不能与外部类重名
5、静态内部类不能访问外部类的非静态的属性和方法。外部类不能访问内部类的非静态的属性和方法。
(把静态内部类当做外部类的静态方法来看)
public class StaticMain {
public static void main(String[] args) {
// 构造静态内部类对象
Outer2.Inner2 inner2 = new Outer2.Inner2();
inner2.innerShow();
Outer2 outer2 = new Outer2();
outer2.outerShow();
}
}
class Outer2 {
private String name = "zhangsan";
private int num1 = 10;
private static int num3 = 100;
public void outerShow() {
System.out.println(name);
System.out.println(num1);
// 不能访问
// System.out.println(Inner2.name);
// 可以通过内部类对象进行访问
Inner2 inner2 = new Inner2();
System.out.println(inner2.name);
// 可以访问内部类中的静态属性
System.out.println(Inner2.num3);
}
public static class Inner2 {
private String name = "lisi";
private int num2 = 20;
private static int num3 = 30;
public void innerShow() {
// 静态内部类不能访问外部类中非静态成员
// System.out.println(Outer2.this.name);
// 可以访问自己内部的
System.out.println(num2);
// 通过类名访问
System.out.println(Outer2.num3);
}
}
}
匿名内部类
1、匿名内部类是没有名称的内部类,没有办法引用它们。必须在创建的时候作为new语句的一部分来声明并创建它们的实例。
2、匿名内部类必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口。如果父类(或者父接口)是抽象类,则匿名内部类必须实现其所有的抽象方法。
3、匿名内部类中可以定义代码块{},用于实例的初始化(代码块优先构造方法先执行),但是不能定义静态代码块。
4、new interface/superclass{ }
这种形式的new语句声明一个新的匿名类,它对一个给定的类进行扩展,或者实现一个给定的接口,并同时创建该匿名类的一个新实例。new 出来的是接口/抽象类的实现类对象。
5、接口/抽象类绝对不能实例化。
public class AnonymousInnerClass {
public static void main(String[] args) {
Person person = new Person();
Animal dog = new Dog();
person.feed(dog);
person.feed(new Animal() {
@Override
public void eat() {
System.out.println("吃鱼");
}
});
new Animal() {
// 匿名内部类中可以有自己的属性
private String name = "dog";
// static不能有静态代码块
{
name = "haha";
}
@Override
public void eat() {
System.out.println("吃鱼");
}
// 匿名内部类中可以有自己的方法
public void show() {
System.out.println("show " + name);
}
}.show();// 调用自己的方法,只能通过这个方法
}
}
class Person {
// 多态
public void feed(Animal animal) {
animal.eat();
}
}
abstract class Animal {
public abstract void eat();
}
class Dog extends Animal {
@Override
public void eat() {
System.out.println("啃骨头");
}
}
局部内部类
1、局部内部类使用最少。
2、定义在代码块{},方法体内的类叫局部内部类。
3、局部内部类访问外部类的属性和方法使用“外部类名.this.属性名”和“外部类名.this.方法名(参数)”的形式。
4、对外部世界完全隐藏,只能在其作用域内生成对象。只能在方法体,代码块中构造。
5、局部类不能加访问修饰符,因为它们不是类成员。可以看做是局部变量。只有属性或者说是类的成员才能加访问修饰符。
6、成员内部类不能与外部类重名。
7、局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰。也就是说局部内部类只能访问方法或者语句块中声明的常量。
public class LocalInnerClass {
public static void main(String[] args) {
Outer3 outer3 = new Outer3();
outer3.showOuter();
}
}
class Outer3 {
private String name = "zhangsan";
private int num1 = 10;
private static int num2 = 20;
public void showOuter() {
int num4 = 50;
final int num5 = 60;
// 局部内部类不能加访问修饰符
//局部内部类的声明周期很短,只在方法的语句块中有效
//方法运行完,局部内部类对象释放
class Inner3 {
private int num3 = 30;
private int num1 = 20;
public void showInner() {
System.out.println(num3);
//自己的num1
System.out.println(num1);
//可以访问到
System.out.println(Outer3.this.num1);
System.out.println(Outer3.num2);
//局部内部类只能访问声明其方法中的常量final
// System.out.println(num4);
System.out.println(num5);
}
}
// 方法从上向下执行,只能在class之后创建,外部能不能使用Inner3
Inner3 inner3 = new Inner3();
inner3.showInner();
}
}