内部类的基本概念
内部类:就是在一个类的内部进行其他类结构的嵌套操作
内部类的使用暂时不作为设计的首选。内部类的特点如下
- 破坏了程序的结构
- 方便进行私有属性的访问。(外部类也可以访问内部类的私有域)
- 如果发现类名称上出现了".",应当立即想到内部类的概念。
内部类为什么存在?
1.内部类方法可以访问该类定义所在作用域中的数据,包括被private修饰的私有数据
2.内部类可以对同一个包中的其他类隐藏起来
3.内部类可以实现 java 单继承的缺陷(通过在类中定义多个内部类来继承多个父类)
4. 当我们想要定义一个回调函数却不想写大量代码的时候我们可以选择使用匿名内部类来实现(回调函数就是我把我的函数地址以一个参数的形式传给另一个函数,然后这个函数又调用我。举个例子,我很懒,早上总是上学迟到。为了早起我叫我妈六点半叫我起床,我妈可以通过推我叫醒我,可以用铃声叫醒我,叫醒的方式由我来决定)
范例:内部类访问外部类所有作用域中的数据
class Outer{
private String msg = "Hello World" ;
// ********************************
class Inner{ //定义一个内部类
public void print(){ //定义一个普通方法
System.out.println(msg); //调用msg属性
}
}
// ********************************
//在外部类中定义一个方法,该方法负责产生内部类对象并且调用print()方法
public void fun(){
Inner in = new Inner(); //内部类对象
in.print(); // 内部类提供的print()方法
}
}
public class Test{
public static void main(String[] args) {
Outer out = new Outer(); //外部类对象
out.fun(); //外部类方法
}
}
范例:使用内部类来实现“多继承”
class A {
private String name = "A类的私有域";
public String getName() {
return name;
}
}
class B {
private int age = 20;
public int getAge() {
return age;
}
}
class Outter {
private class InnerClassA extends A {
public String name() {
return super.getName();
}
}
private class InnerClassB extends B {
public int age() {
return super.getAge();
}
}
public String name() {
return new InnerClassA().name();
}
public int age() {
return new InnerClassB().age();
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
System.out.println(outter.name());
System.out.println(outter.age());
}
}
内部类与外部类的关系
1.对于非静态内部类,内部类的创建依赖外部类的实例化对象,在没有外部类实例化对象之前是无法创建内部类的
2.内部类是一个相对独立的实体,与外部类不是“is-a”关系
3.内部类可以直接访问外部类元素(包括私有域),但是外部类不可以直接访问内部类的元素
4.外部类可以通过内部类引用间接访问内部类元素
范例:内部类可以直接访问外部类的元素
class Outter {
private String outName;
private int outAge;
class Inner {
private int InnerAge;
public Inner() {
Outter.this.outName = "I am Outter class";
Outter.this.outAge = 20;
}
public void display() {
System.out.println(outName);
System.out.println(outAge);
}
}
}
public class Test {
public static void main(String[] args) {
Outter.Inner inner = new Outter().new Inner();
inner.display();
}
}
创建内部类
1.在外部类外部创建内部类语法
Outter outter=new Outter();
Outter.Inner inner1=outter.new Inner();
Outter.Inner inner = new Outter().new Inner();
2.在外部类内部创建内部类语法
Inner in = new Inner();
内部类分类
成员内部类
位于另一类的内部(就像是外部类的一个成员)
class Circle {
double radius = 0;
public Circle(double radius) {
this.radius = radius;
}
class Draw { //内部类
public void drawSahpe() {
System.out.println("drawshape");
}
}
}
注意:
1.成员内部类中不能存在任何static的变量和方法
2.成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类
3.成员内部类可以无条件访问外部类的所有成员属性和成员方法(包括private成员和静态成员)
4.当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。如果要访问外部类的同名成员,需要以下面的形式进行访问:
外部类.this.成员变量
外部类.this.成员方法
5.内部类可以拥有private访问权限、protected访问权限、public访问权限及包访问权限。比如上面的例子,如果成员内部类Inner用private修饰,则只能在外部类的内部访问,如果用public修饰,则任何地方都能访问;如果用protected修饰,则只能在同一个包下或者继承外部类的情况下访问;如果是默认访问权限,则只能在同一个包下访问。这一点和外部类有一点不一样,外部类只能被public和包访问两种权限修饰。我个人是这么理解的,由于成员内部类看起来像是外部类的一个成员,所以可以像类的成员一样拥有多种权限修饰。
静态内部类
静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围类,但是静态内部类却没有。没有这个引用就意味着:
- 静态内部类的创建是不需要依赖于外围类,可以直接创建
- 静态内部类不可以使用任何外围类的非static成员变量和方法,而内部类则都可以
class Outer{
private static String msg = "Hello World" ;
// ********************************
static class Inner{ //定义一个内部类
public void print(){ //此时只能使用外部类中的static操作
System.out.println(msg); //调用msg属性
}
}
// ********************************
//在外部类中定义一个方法,该方法负责产生内部类对象并且调用print()方法
public void fun(){
Inner in = new Inner(); //内部类对象
in.print(); // 内部类提供的print()方法
}
}
public class Test{
public static void main(String[] args) {
Outer.Inner in = new Outer.Inner();
in.print();
}
}
方法内部类
定义在外部类的方法中(l类似局部变量)
方法内部类和成员内部类基本一致,就是作用域不同,方法内部类只能在该方法中被使用,出了方法就会失效
对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类。
注意:
- 局部内类不允许使用访问权限修饰符 public private protected 均不允许
- 局部内部类对外完全隐藏,除了创建这个类的方法可以访问它其他的地方是不允许访问的。
- 局部内部类要想使用方法形参,该形参必须用final声明(JDK8形参变为隐式final声明).
package hhh.Test;
class Outter {
private int num;
public void display(int test) {
class Inner {
private void fun() {
num++;
System.out.println(num);
System.out.println(test);
}
}
new Inner().fun();
}
}
public class Test {
public static void main(String[] args) {
Outter out = new Outter();
out.display(20);
}
}
匿名内部类
顾名思义就是一个没有名字的方法内部类,所以符合方法内部类的所有约束
注意
- 匿名内部类是没有访问修饰符的。
- 匿名内部类必须继承一个抽象类或者实现一个接口
- 匿名内部类中不能存在任何静态成员或方法
- 匿名内部类是没有构造方法的,因为它没有类名。
- 与局部内部相同匿名内部类也可以引用方法形参。此形参也必须声明为 final
在一个类只使用一次的时候,就写为匿名内部类,用来简化代码的编写
interface MyInterface {
void test();
}
class Outter {
private int num;
public void display(int para) {
// 匿名内部类,实现了MyInterface接口
new MyInterface(){
@Override
public void test() {
System.out.println("匿名内部类"+para);
}
}.test();
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.display(20);
}
}