【JAVA 核心编程】面向对象高级:类变量与方法 抽象类与接口
一、类变量与类方法(静态变量)
1)类变量
class Child{private String name;//定义一个变量count,是一个类变量(静态变量)static静态//该变量最大的特点就是会被Child 类的所有对象访问public static int count = 0;public Child(String name){this.name = name;}public void join(){System.out.println(name+"加入了游戏");}
}
1.什么是类变量
类变量也叫静态变量/静态属性
,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的
对象去修改它时,修改的也是同一个变量。这个从前面的图也可看出来。
2.如何定义类变量
定义语法:
访问修饰符 static 数据类型 变量名;
[推荐]
static 访问修饰符 数据类型 变量名;
class A{public static string name ="abc";static public int totalNum = 100;
}
3.如何访问类变量
类名.类变量名
推荐
或者 对象名.类变量名
【静态变量的访问修饰符的访问权限和范围 和 普通属性是一样的。】
4.类变量注意事项和细节
1.什么时候需要用类变量,当我们需要让某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量);
比如:定义学生类,统计所有学生共交多少钱。Student(name,staticfee)
2.类变量与实例变量(普通属性)区别类变量是该类的所有对象共享的,而实例变量是每个对象独享的
3.加上static称为类变量或静态变量,否则称为实例变量/普通变量/非静态变量
4.类变量可以通过 类名.类变量名 或者 对象名.类变量名 来访问,但java设计者 推荐我们使用 类名.类变量名方式访问。
【前提是 满足访问修饰符的访问权限和范围】
5.实例变量不能通过 类名.类变量名 方式访问。
6.即使你没有创建对象,类变量是在类加载时就初始化了,也就是说,只要类加载了,就可以使用类变量了。【案例演示]
7.类变量的生命周期是随类的加载开始随着类消亡而销毁.
2)类方法基本介绍
1.类方法也叫静态方法
形式如下:
访问修饰符 static 数据返回类型 方法名()){ }【推荐】
static 访问修饰符 数据返回类型 方法名(){ }
类方法的调用使用方式: 类名.类方法名 或者 对象名.类方法名 【前提是 满足访问修饰符的访问权限和范围】
静态方法可以访问静态属性/变量
class B{public static void printstart(){System.out.println("打印星星..”);} }
如果我们希望不创建实例/对象,也可以调用某个方法(当工具来用)
这时,把方法做成静态方法时非常合适
2.类方法使用场景
当方法中不涉及到任何和对象相关的一个成员,则可以将方法设计成静态方法,提高开发效率
比如:Math类,Arrays类 可以ctrl + b 查看他们的源码
在实际开发中,往往会将一些通用的方法,设计成静态方法,无需创建对象就可以使用该方法
例如:冒泡排序,打印一维数组
3)类变量与类方法
1.类方法和普通方法都是随着类的加载而加载,将结构信息储存在方法区
类方法中无this的参数
普通方法中隐含着this参数
2.类方法可以通过类名调用,也可以通过对象名调用。
3.普通方法和对象有关,需要通过对象名调用,比如:对象名.方法名(参数),不能通过类名调用。
4.类方法中不允许使用和对象有关的关键字,比如super和this。普通方法(成员方法)可以。
5.类方法(静态方法)中,只能访问静态变量 或 静态方法。
6.普通成员方法,既可以访问静态变量(方法),可以访问普通变量(方法)。
二、main方法理解
1)介绍
2)理解main方法语法
特别提示
-
在 main()方法中,我们可以直接调用 main 方法所在类的静态方法或静态属性。
-
但是,不能直接访问该类中的非静态成员,必须创建该类的一个实例对象后,才能通过这个对象去访问类中的非静态成员
-
代码:
public class Main {//静态的变量/属性private static String name = "你好";//非静态的变量/属性private int n1 = 10000;//静态方法public static void hi() {System.out.println("Main 的 hi 方法");}//非静态方法public void cry() {System.out.println("Main 的 cry 方法");}public static void main(String[] args) {
//可以直接使用 name
//1. 静态方法 main 可以访问本类的静态成员System.out.println("name=" + name);hi();//2. 静态方法 main 不可以访问本类的非静态成员//System.out.println("n1 = " + n1);//错误//cry();//3. 静态方法 main 要访问本类的非静态成员,需要先创建对象 , 再调用即可Main main = new Main();System.out.println(main.n1);//okmain01.cry();}
}
3)main方法动态传值
public class CommandPara {public static void main(String[] args) {for (int i = 0; i < args.length; i++) {System.out.println("args[" + i + "]=" + args[i]);}}
}
旧页面
三、代码块
1)基本介绍
代码化块又称为初始化块,属于类中的成员[即 是类的一部分],类似于方法,将逻辑语句封装在方法体中,通过包围起来。
但和方法不同,没有方法名,没有返回,没有参数,只有方法体,而且不用通过对象或类显式调用,而是加载类时,或创建对象时隐式调用。
基本语法[修饰符]{代码
}
注意:
1)修饰符 可选,要写的话,也只能写 static。
2)代码块分为两类,使用static 修饰的叫静态代码块,没有static修饰的,叫普通代码块。
3)逻辑语句可以为任何逻辑语句(输入、输出、方法调用、循环、判断等)。
4);号可以写上,也可以省略。
1.理解:
1)相当于另外一种形式的构造器(对构造器的补充机制),可以做初始化的操作
2)场景: 如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性
2.代码演示:
public class CodeBlock01 {public static void main(String[] args) {Movie movie = new Movie("你好,李焕英");System.out.println("===============");Movie movie2 = new Movie("唐探 3", 100, "陈思诚");}
}class Movie {private String name;private double price;private String director;// 3 个构造器 -> 重载//解读//(1) 下面的三个构造器都有相同的语句//(2) 这样代码看起来比较冗余//(3) 这时我们可以把相同的语句,放入到一个代码块中,即可//(4) 这样当我们不管调用哪个构造器,创建对象,都会先调用代码块的内容//(5) 代码块调用的顺序优先于构造器{System.out.println("电影屏幕打开...");System.out.println("广告开始...");System.out.println("电影正是开始...");};public Movie(String name) {System.out.println("Movie(String name) 被调用...");this.name = name;}public Movie(String name, double price) {this.name = name;this.price = price;}public Movie(String name, double price, String director) {System.out.println("Movie(String name, double price, String director) 被调用...");this.name = name;this.price = price;this.director = director;}
}
2)代码块使用细节和讨论
1.细节一
public class CodeBlockDetail01 {public static void main(String[] args) {//类被加载的情况举例// 1. 创建对象实例时(new)// AA aa = new AA();// 2. 创建子类对象实例,父类也会被加载, 而且,父类先被加载,子类后被加载// AA aa2 = new AA();// 3. 使用类的静态成员时(静态属性,静态方法)// System.out.println(Cat.n1);// static 代码块,是在类加载时,执行的,而且只会执行一次. // DD dd = new DD();// DD dd1 = new DD();// 普通的代码块,在创建对象实例时,会被隐式的调用。// 被创建一次,就会调用一次// 如果只是使用类的静态成员时,普通代码块并不会执行System.out.println(DD.n1);//8888, 静态模块块一定会执行}
}
class DD {public static int n1 = 8888;//静态属性//静态代码块static {System.out.println("DD 的静态代码 1 被执行...");//}
//普通代码块, 在 new 对象时,被调用,而且是每创建一个对象,就调用一次//可以这样简单的,理解 普通代码块是构造器的补充{System.out.println("DD 的普通代码块...");}
}
class Animal {//静态代码块static {System.out.println("Animal 的静态代码 1 被执行...");//}
}
class Cat extends Animal {public static int n1 = 999;//静态属性//静态代码块static {System.out.println("Cat 的静态代码 1 被执行...");//}
}
class BB {//静态代码块static {System.out.println("BB 的静态代码 1 被执行...");//1}
}
class AA extends BB {//静态代码块static {System.out.println("AA 的静态代码 1 被执行...");//2}
}
2.细节二
public class CodeBlockDetail02 {public static void main(String[] args) {A a = new A();//执行顺序// (1) A 静态代码块 01 // (2) getN1 被调用...// (3) A 普通代码块 01// (4) getN2 被调用...// (5) A() 构造器被调用}
}
class A {{ //普通代码块System.out.println("A 普通代码块 01");} private int n2 = getN2();//普通属性的初始化static { //静态代码块System.out.println("A 静态代码块 01");}//静态属性的初始化private static int n1 = getN1();public static int getN1() {System.out.println("getN1 被调用...");return 100;}public int getN2() { //普通方法/非静态方法System.out.println("getN2 被调用...");return 200;}//无参构造器public A() {System.out.println("A() 构造器被调用");}
}
3.细节三
构造器 的最前面其实隐含了 super() 和 调用普通代码块,静态相关的代码块,属性初始化,在类加载时,就执行完毕。
因此是优先于 构造器和普通代码块执行。
class A {public A(){//构造器//这里有隐藏的执行要求//隐藏的 super();//调用普通代码块System.out.println("ok"");}
}
public class CodeBlockDetail03 {public static void main(String[] args) {new BBB();//(1)AAA 的普通代码块//(2)AAA() 构造器被调用//(3)BBB 的普通代码块//(4)BBB() 构造器被调用}
}class AAA { //父类 Object{System.out.println("AAA 的普通代码块");}public AAA() {//(1)super()//(2)调用本类的普通代码块System.out.println("AAA() 构造器被调用....");}}class BBB extends AAA {{System.out.println("BBB 的普通代码块...");}public BBB() {//(1)super()//(2)调用本类的普通代码块System.out.println("BBB() 构造器被调用....");}
}
4.细节四
1)我们看一下创建一个子类时(继承关系),他们的静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法的调用顺序如下:
- 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)
- 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类的构造方法 // 面试题
- 静态方法与普通方法只有在调用时才执行,与顺序无关
2)静态代码块只能直接调用静态成员(静态属性和静态方法),普通代码块可以调用任意成员。
public class CodeBlockDetail04 {public static void main(String[] args) {//说明//(1) 进行类的加载//1.1 先加载 父类 A02 1.2 再加载 B02//(2) 创建对象//2.1 从子类的构造器开始new B02();//对象new C02();}
}class A02 { //父类private static int n1 = getVal01();static {System.out.println("A02 的一个静态代码块..");//(2)}{System.out.println("A02 的第一个普通代码块..");//(5)}public int n3 = getVal02();//普通属性的初始化public static int getVal01() {System.out.println("getVal01");//(1)return 10;}public int getVal02() {System.out.println("getVal02");//(6)return 10;}public A02() {//构造器//隐藏//super()//普通代码和普通属性的初始化...... System.out.println("A02 的构造器");//(7)}
}class C02 {private int n1 = 100;private static int n2 = 200;private void m1() {}private static void m2() {}static {//静态代码块,只能调用静态成员//System.out.println(n1);错误System.out.println(n2);//ok//m1();//错误m2();}{//普通代码块,可以使用任意成员System.out.println(n1);System.out.println(n2);//okm1();m2();}
}class B02 extends A02 { //private static int n3 = getVal03();static {System.out.println("B02 的一个静态代码块..");//(4)}public int n5 = getVal04();{System.out.println("B02 的第一个普通代码块..");//(9)}System.out.println("getVal03");//(3)return 10;
}public int getVal04() {System.out.println("getVal04");//(8)return 10;}// public B02() {//构造器//隐藏了//super()//普通代码块和普通属性的初始化... System.out.println("B02 的构造器");//(10)// TODO Auto-generated constructor stub
}
四、单例设计模式
1)介绍
1.静态方法和属性的经典使用
2.设计模式是在大量的实践中总结和理论化之后优选的代码结构、编程风格以及解决问题的思考方式。
设计模式就像是经典的棋谱,不同的棋局,我们用不同的棋谱,免去我们自己再思考和摸索
2)什么是单例模式
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,
并且该类只提供一个取得其对象实例的方法
单例模式有两种方式:
1)饿汉式
2)懒汉式
3)单例模式
步骤如下:
1)构造器私有化 -> 防止直接 new
2)类的内部创建对象
3)向外暴露一个静态的公共方法。getInstance
1.饿汉式
public class SingleTon01 {public static void main(String[] args) {// GirlFriend xh = new GirlFriend("小红");// GirlFriend xb = new GirlFriend("小白");//通过方法可以获取对象GirlFriend instance = GirlFriend.getInstance();System.out.println(instance);GirlFriend instance2 = GirlFriend.getInstance();System.out.println(instance2);//两个对象是一样的System.out.println(instance == instance2);//T}
}//有一个类, GirlFriend//只能有一个女朋友class GirlFriend {private String name;//为了能够在静态方法中,返回 gf 对象,需要将其修饰为 static//对象,通常是重量级对象, 饿汉式可能造成创建了对象,但是沒有使用. private static GirlFriend gf = new GirlFriend("小红红");//如何保障我们只能创建一个 GirlFriend 对象//步骤[单例模式-饿汉式]//1. 将构造器私有化//2. 在类的内部直接创建对象(该对象是 static)//3. 提供一个公共的 static 方法,返回 gf 对象private GirlFriend(String name) {System.out.println("构造器被調用.");this.name = name;}public static GirlFriend getInstance() {return gf;}@Overridepublic String toString() {return "GirlFriend{" +"name='" + name + '\'' +'}';}}
2.懒汉式
public class SingleTon02 {public static void main(String[] args) {//new Cat("大黃");//System.out.println(Cat.n1);Cat instance = Cat.getInstance();System.out.println(instance);//再次调用 getInstanceCat instance2 = Cat.getInstance();System.out.println(instance2);System.out.println(instance == instance2);//T}}
//希望在程序運行過程中,只能創建一個 Cat 對象//使用单例模式class Cat {private String name;//public static int n1 = 999;private static Cat cat; //默认是 null//步驟//1.仍然构造器私有化//2.定义一个 static 静态属性对象//3.提供一个 public 的 static 方法,可以返回一个 Cat 对象//4.懒汉式,只有当用户使用 getInstance 时,才返回 cat 对象, 后面再次调用时,会返回上次创建的 cat 对象// 从而保证了单例private Cat(String name) {System.out.println("构造器调用...");this.name = name;}public static Cat getInstance() {if (cat == null) {//如果还沒有创建 cat 对象cat = new Cat("小可爱");}return cat;}@Overridepublic String toString() {return "Cat{" +"name='" + name + '\'' +'}';}}
4)懒汉与饿汉区别
饿汉:想要好多好多,不需要用的也想要;
懒汉:用不着就不要了,要用的时候再创建;
二者最主要的区别在于创建对象的时机不同:
- 饿汉式是在类加载就创建了对象实例,而懒汉式是在使用时才创建。
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题。
- 饿汉式存在浪费资源的可能。因为如果程序员一个对象实例都没有使用,那么饿汉式创建的对象就浪费了,懒汉式是使用时才创建,就不存在这个问题。
- 在我们javaSE标准类中,java.lang.Runtime就是经典的单例模式。
五、Final基本使用
1)介绍
final 中文意思:
最后的,最终的.
final 可以修饰类、属性、方法和局部变量,
在某些情况下,程序员可能有以下需求,就会使用到final:
1)当不希望类被继承时,可以用final修饰。【案例演示】
//如果我们要求A类不能被其他类继承
//可以使用final修饰 A类final class A {}
class B extends A {}//错误
2)当不希望父类的某个方法被子类覆盖/重写(override)时,可以用final关键字修饰。【案例演示: 访问修饰符 final 返回类型 方法名】
3)当不希望类的的某个属性的值被修改,可以用final修饰。【案例演示: public final double TAX RATE=0.08】
4)当不希望某个局部变量被修改,可以使用final修饰。【案例演示: final doubleTAX RATE=0.08】
注意:
1.final必须在定义时初始化
2.final可修饰类、属性、方法
在Java中,final
关键字可以用于以下场景:
- 修饰类,表示该类不能被继承。
- 修饰方法,表示该方法不能被子类重写。
- 修饰变量(无论是实例变量、类变量或局部变量),表示该变量的值一旦赋值后就不能再改变。
2)重点
1)final修饰的属性又叫常量,一般 用 XX_XX_XX 来命名
2)final修饰的属性在定义时,必须赋初值,并且以后不能再修改,赋值可以在如下位置之一【选择一个位置赋初值即可】:
- 定义时:如 public final double TAX RATE=0.08:
- 在构造器中
- 在代码块中
3)如果final修饰的属性是静态的,则初始化的位置只能是
- 定义时
- 在静态代码块,不能在构造器中赋值。
4)final类不能继承,但是可以实例化对象。[A2类]
5)如果类不是final类,但是含有final方法,则该方法虽然不能重写,但是可以被继承。[A3类]
6)一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法
7)final不能修饰构造方法(即构造器)
8)final 和 static 往往搭配使用,效率更高,底层编译器做了优化处理。
class Demo{public static final int i=16; static{System.out.println("你好~");}
}
9)包装类(Integer,Double,Float,Boolean等都是final),String也是final类。
六、抽象类与接口
1)抽象类
父类方法的不确定性
当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类
但有一个类中存在抽象方法时,需要将该类声明为abstract类
abstract class Animal{String name;int age;abstract public void cry();
}
抽象类的价值更多作用在于设计,是设计者设计好后,让子类继承并实现抽象类()
- 抽象类不能被实例化
- 抽象类不一定包含了abstract方法,抽象类可以没有abstract方法
- 一旦包含了abstract方法,则这个类必须声明为abstract
- abstract只能修饰类和方法,不能修饰属性和其他的
- 抽象类可以有任意成员、静态属性等等
- 抽象方法不能有主体,即不能实现.如图所示
abstract void aaa(){};//{}错误
-
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类
-
抽象方法不能使用private, final,和static来修饰,因为这些关键字都是和重写相违背的
实际上,abstract
可以修饰类和方法,但不能修饰属性。abstract
修饰的类称为抽象类,不能被实例化;
修饰的方法称为抽象方法,没有具体实现(没有方法体)。
2)接口 interface
1.基本介绍:
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,再根据具体情况把这些类写出来。
//定义接口
interface 接口名{//属性//方法
}//实现接口
class 类名 implements 接口{自己属性;自己方法;必须实现的接口抽象方法;
}
主函数
public class Main {public static void main(String[] args) {}
}//如果一个类 implements 实现接口
//需要将该接口中所有的抽象方法都实现
//快捷键实现该方法 鼠标放在红色波浪线处,按下alt+enter键
class A implements Ainterface{@Overridepublic void h1() {System.out.println("h1");}
}
public interface Ainterface {public int n1 = 10;//在抽象方法中可以省略abstract关键字public void h1();//在jdk8之后,可以有默认实现方法,需要使用default关键字修饰default public void h2(){System.out.println("h2");}//在jdk8之后,可以有静态方法public static void cry(){System.out.println("cry");}
}
2.使用细节
1.接口不能被实例化,向上转型
2.接口中所有的方法是public方法,接口中抽象方法,可以不用abstract修饰
3.一个普通类实现接口,就必须将该接口的所有方法都实现
4.抽象类去实现接口,可以不用实现接口的方法
5.一个类可以实现多个接口
6.接口中的属性,只能是final的,而且是 public static final 修饰符。 比如int a=1;
实际上是 public static final int a=1;(必须初始化)
7.接口中属性的访问形式: 接口名.属性名
8.一个接口不能继承其它的类,但是可以继承多个别的接口[举例]
interface A extends B,C{}
9.接口的修饰符 只能是 public 和默认,这点和类的修饰符是一样的。
10.接口名必须与文件名相同
3)接口和继承区别
当子类继承了父类,就自动的拥有父类的功能
如果子类需要扩展功能,可以通过实现接口的方式扩展.
可以理解 实现接口 是 对 java 单继承机制的一种补充
4)接口的多态特性
七、内部类
1)基本介绍
一个类的内部又完整的嵌套了另一个类结构。被嵌套的类称为内部类(inner class),嵌套其他类的类称为外部类(outer class)。是我们类的第五大成员【思考:类的五大成员是哪些?[属性、方法、构造器、代码块、内部类]】,内部类最大的特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系,注意:内部类是学习的难点,同时也是重点,后面看底层源码时,有大量的内部类。
2)基本语法
class Outer{ //外部类class Inner{//内部类}
}
class Other{//外部其他类
}
3)内部类分类
定义在外部类局部位置上(比如方法内):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点!!!)
定义在外部类的成员位置上:
- 成员内部类(没用static修饰)
- 静态内部类(使用static修饰)
4)局部类的使用
说明:局部内部类是定义在外部类的局部位置,比如方法中,并且有类名
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,因为它的地位就是一个局部变量。局部变量是不能使用修饰符的。但是可以使用final 修饰,因为局部变量也可以使用final。
- 作用域:仅仅在定义它的方法或代码块中。
- 局部内部类—访问---->外部类的成员 [访问方式:直接访问]
- 外部类—访问---->局部内部类的成员访问方式:创建对象,再访问(注意:必须在作用域内)
记住:
(1) 局部内部类定义在方法中/代码块
(2) 作用域在方法体或者代码块中
(3) 本质仍然是一个类
-
外部其他类—不能访问----->局部内部类(因为 局部内部类地位是一个局部变量)
-
如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,则可以使用(外部类名.this.成员)去访问
System.out.println("外部类的n2="+ 外部类名.this.n2);
/** * 演示局部内部类的使用 */
public class LocalInnerClass {public static void main(String[] args) { //演示一遍 Outer02 outer02 = new Outer02(); outer02.m1(); System.out.println("outer02 的 hashcode=" + outer02); }
}
class Outer02 {//外部类 private int n1 = 100; private void m2() { System.out.println("Outer02 m2()"); }//私有方法 public void m1() {//方法 //1.局部内部类是定义在外部类的局部位置,通常在方法 //3.不能添加访问修饰符,但是可以使用 final 修饰 //4.作用域 : 仅仅在定义它的方法或代码块中 final class Inner02 {//局部内部类(本质仍然是一个类) //2.可以直接访问外部类的所有成员,包含私有的 private int n1 = 800; public void f1() { //5. 局部内部类可以直接访问外部类的成员,比如下面 外部类 n1 和 m2()//7. 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,
// 使用 外部类名.this.成员 去访问
// Outer02.this 本质就是外部类的对象, 即哪个对象调用了 m1, Outer02.this 就是哪个对象 System.out.println("n1=" + n1 + " 外部类的 n1=" + Outer02.this.n1); System.out.println("Outer02.this hashcode=" + Outer02.this); m2(); } }
//6. 外部类在方法中,可以创建 Inner02 对象,然后调用方法即可 Inner02 inner02 = new Inner02(); inner02.f1(); }
}
5)匿名内部类的使用(重要)
(1)本质是类
(2)内部类
(3)该类没有名字
(4)同时还是一个对象说明:匿名内部类是定义在外部类的局部位置,比如方法中,并且没有类名
- 匿名内部类的基本语法
new 类或接口(参数列表){类体
}
- 匿名内部类的语法比较奇特,请大家注意,因为匿名内部类既是一个类的定义同时它本身也是一个对象,因此从语法上看,它既有定义类的特征,也有创建对象的特征,对前面代码分析可以看出这个特点,因此可以调用匿名内部类方法
- 可以直接访问外部类的所有成员,包含私有的。
- 不能添加访问修饰符,因为它的地位就是一个局部变量。[过]
- 作用域:仅仅在定义它的方法或代码块中。[过]
- 匿名内部类—访问---->外部类成员。[访问方式:直接访问]
- 外部其他类—不能访问----->匿名内部类(因为 匿名内部类地位是一个局部变量)。
- 如果外部类和匿名内部类的成员重名时,匿名内部类访问的话,默认遵循就近原则如果想访问。外部类的成员,则可以使用(外部类名.this.成员)去访问。