在说内部类之前提一下成员方法、静态方法、普通方法。因为内部类和成员方法很相似
成员方法:成员方法不能存在静态变量,成员方法可以访问静态变量。
静态方法:静态方法可以存在静态变量,静态方法不能访问普通变量。
静态方法不能访问类中普通属性(静态方法没有对象产生,普通属性和对象有关),但是静态方法可以访问静态属性
普通方法可以访问类中静态属性,但是普通方法可访问类中普通属性
内部类
定义:在一个类中进行其他类结构的嵌套。
内部类的优点:
(1)、内部类和外部类可以相互访问彼此的私有域。
(2)、内部类可以实现java的单继承局限。
(3)、内部类可以对同一包中的其他类隐藏起来,仅供外部类使用(保护性)
内部类的缺点: 结构复杂
内部类分类:
1、普通内部类(在类内部): 看代码
class Outter {
private String msg1 = "外部类的私有域";
// ----------------------------------
// 内部类
class Inner {
public void fun() {
System.out.println(msg1);
}
}
// ----------------------------------
// 普通外部类
public void test() {
Inner in = new Inner(); // 声明并实例化一个内部类
in.fun(); // 调用内部类的而普通方法
}
}
public class Test {
public static void main(String[] args) {
Outter out = new Outter();
out.test();
}
}
总结:在内部类中调用成员变量与成员方法类似:成员方法调用类中的成员变量,直接调用(没有对象),内部类也是一样的,直接调用。
1.1 普通内部类(在外部调用内部类): 看代码
class Outter {
private String msg = "外部类的私有域";
// 扩展一个get方法,方便外部类调用
public String getMsg() {
return msg;
}
// 普通外部类
public void test() { // 2
// this表示当前对象
Inner in = new Inner(this); // 3 // 声明并实例化一个内部类
in.fun(); // 5 // 调用内部类的而普通方法
}
}
// 内部类
// // 因为主类的属性是封装起来的,要在外部调用,需要使用get方法。
class Inner {
private Outter out; // Inner类中的外部对象
public Inner(Outter out) { // 4
this.out = out; // 通过构造方法传入out对象
}
public void fun() { // 6
System.out.println(out.getMsg()); // 此处调用msg需要对象来调用,所以Inner中要有一个外部类的对象
}
}
public class Test{
public static void main(String[] args) {
Outter out = new Outter(); // 1
out.test(); // 2
}
}
1.3 内部类实现多继承:java不允许多继承,但是内部类可以。
class A {
private String msg = " A 的属性";
public String getMsg() {
return msg;
}
}
class B {
private String age = " B 的属性";
public String getAge() {
return age;
}
}
class C {
// 在C的内部,继承了A和B
// ---------------------------------------
class InnerclassA extends A {
public String name() {
return super.getMsg(); // 通过super访问父类同名的方法
}
}
class InnerclassB extends B {
public String age() {
return super.getAge();
}
}
// --------------------------------------
// 外部类
public String name() {
// 在外部类中声明方法,调用内部类
return new InnerclassA().name();
}
public String age() {
return new InnerclassB().age();
}
}
public class Test{
public static void main(String[] args) {
C c = new C();
System.out.println(c.name());
System.out.println(c.age());
}
}
2、内部类与外部类的关系:(在外部类之外)
(1)、对于非静态内部类而言,内部类的创建需要依赖于外部类的实例化对象,在没有外部类之前是无法创建内部类的。
(2)、内部类是一个相对独立的个体,与外部类不是is-a关系。
(3)、内部类可以直接访问外部类的元素(包含私有域),外部类不可以直接访问内部类元素,需要通过内部类的引用间接访问。
2.1 内部类直接访问外部元素,外部类引用访问内部类
class Outter {
private String msg1 = "外部类的私有域";
// 普通内部类
class Inner {
// 内部类的私有域
private String msg2 = "内部类的私有域";
public void fun() {
System.out.println(msg1);// 普通内部类调用外部类的方法
}
}
// 普通外部类
public void test() {
// 外部类不能直接调用内部类,需要通过对象引用间接调用
Inner in = new Inner();
in.fun(); // 外部类调用内部类方法
System.out.println(in.msg2); // 外部类调用内部类私有域
}
}
public class Test{
public static void main(String[] args) {
Outter out = new Outter();
out.test();
}
}
3、创建内部类的语法(在外部类之外):
(1)、创建非静态内部类(普通内部类)的语法:
外部类.内部类 内部类对象引用 = new 外部类().new内部类();
eg: Outter.Inner in = new Outter().new Inner();
(2)、创建静态内部类语法:
外部类.内部类 内部类对象引用 = new 外部类.内部类();
eg: Outter.Inner in = new Outter.Inner();
代码示例:
(1)创建非静态内部类语法:
class Outter {
private String msg1 = "外部类的私有域";
// 普通内部类
class Inner {
public void fun() {
System.out.println(msg1);// 普通内部类调用外部类的方法
}
}
}
public class Test{
public static void main(String[] args) {
// 创建Inner对象
Outter.Inner in = new Outter().new Inner();
in.fun();
}
}
(2)创建静态内部类的语法:
class Outter {
private static String msg = "外部类的私有域";
// 静态内部类
static class Inner {
public void fun() {
System.out.println(msg);// 普通内部类调用外部类的方法
}
}
}
public class Test{
public static void main(String[] args) {
// 直接产生内部类,没有外部类产生
Outter.Inner in = new Outter.Inner(); // -----------------》语法
in.fun();
}
}
4、内部类的分类:
(1)、成员内部类-成员方法
1)、成员内部类不能存在任何static变量或方法,可以访问外部静态域。
2)、成员内部类需要依附外部类new Outter.new Inner();
3)、内部类可以使用private封装,表示私有内部类,该内部类仅供外部类使用。
class Outter {
private String msg1 = "外部类的私有域";
// -------------------------------------------------------
// *****错误代码(创建静态属性)******
// class Inner{
// private static int age = 9;
// }
// -----------------------------------------------------
// 成员内部类
// 访问静态属性
class Inner {
public void fun() {
System.out.println(msg1);// 普通内部类调用外部类的方法
}
}
// 使用private 封装
// 创建私有内部类(仅供外部使用)
private class Inner {
public void fun() {
System.out.println(msg1);// 普通内部类调用外部类的方法
}
}
}
public class Test{
public static void main(String[] args) {
// 创建Inner对象
Outter.Inner in = new Outter().new Inner();
in.fun();
}
}
总结:(1)成员内部类需要依附与外部类创建而创建,如果有静态变量,代表与对象无关
(2)成员内部类不能拥有静态属性(静态属性和对象无关)
(3)但是成员内部类可以访问静态属性
(2)、静态内部类-静态方法
1)、静态内部类的创建不需要外部类,可以直接创建。
2)、静态内部类不可以访问外部类的任何非static域。
class Outter {
private static String msg = "外部类的私有域";
// 静态内部类
static class Inner {
// 静态内部类可以拥有自己的成员变量
private String msg = "静态变量内部的成员变量";
public void fun() {
System.out.println(msg);// 普通内部类调用外部类的方法
}
}
// ----------------------------------------------------------------------
// ===========错误代码=======================
// 静态内部类 不能访问 外部的 非静态 成员变量
// private String msg = "外部类的私有域"; // 非静态属性(外部)
// // 静态内部类
// static class Inner{
// public void fun(){
// System.out.println(msg);// 静态内部类调用外部非静态属性(一定出错)
// }
// }
// -------------------------------------------------------------------
}
public class Test{
public static void main(String[] args) {
// 直接产生内部类,没有外部类产生
Outter.Inner in = new Outter.Inner();
in.fun();
}
}
(3)、方法内部类
1)、方法内部类不能使用任何访问权限修饰符 public、 private 、protected均不允许。
2)、方法内部类对外(方法外)完全隐藏,除了该方法可以访问之外,其余地方均不能访问。
3)、方法内部类想要使用方法形参,该形参必须使用final声明(JDK8变为隐式的final声明)。
class Outter {
private int age = 5;
public void display(int num) { // 此处有一个隐式的final
// 方法内部类
// 只能在该方法中使用
class Inner {
public void fun() {
// num++; // 因为num不能++,证明了final存在
System.out.println(num);
System.out.println(age);
}
}
new Inner().fun(); // 内部类只能在方法内部使用
}
}
public class Test{
public static void main(String[] args) {
Outter outter = new Outter();
outter.display(10);
}
}
总结: 方法内部类的形参为什么修饰成final????
因为方法是在栈针中存储的,使用完后直接弹出。而类的对象是在堆中的,两个空间不相同。
如果方法调用完成后,类还存在(活着),也就是方法都已经弹出栈了,而类的对象还存在, 这是不合理的。所以内部类只能 访问形参,使用final修饰。
(4)、匿名内部类(方法内部类的特殊版本)
1)、匿名内部类必须继承一个抽象类或者实现一个接口。
2)、匿名内部类没有构造方法,因为它没有类名。
interface MyInterface {
void test(); // 抽象方法
}
class Outter {
private int age = 5;
public void display(int num) {
// 内名内部类
new MyInterface() {
@Override
public void test() {
System.out.println(num);
System.out.println(age);
}
}.test(); // 相当于new了一个类,调用它的方法
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.display(10);
}
}
总结: new MyInterface() 代表的不是抽象类,抽象类不能直接new对象,而这里直接使用,代表匿名内部类,实际上隐藏了 class implements。(class implements new MyInterface())