面向对象编程(高级)
1、类变量和类方法
(1) 概念
类变量,也称为静态变量,是指在类级别声明的变量。它们与特定类相关联,而不是与类的实例(对象)相关联。每个类变量只有一份副本,它被类的所有实例共享。
static 变量保存在Class实例的尾部。而class对象确实存在堆中,所以,可以认为,static放在堆中
理解:
static
变量是同一个类所有对象共享static
类变量,在类加载的时候就生成了
类方法(静态方法)是与类本身相关联的方法,而不是与类的实例(对象)相关联。它们可以直接通过类名调用,不需要实例化对象。当方法中不涉及到任何对象相关的成员,就可以将方法设计成静态方法,提高开发效率。
举例:比如工具类里面的方法utils,Math类、Arrays类、Collections集合
(2)定义
类变量语法:
1、 访问修饰符 static 数据类型 变量名;(推荐)
2、 static 访问修饰符 数据类型 变量名;
类方法语法:
1、 访问修饰符 static 数据返回类型 方法名(){};(推荐)
2、 static 访问修饰符 数据返回类型 方法名(){};
(3)访问
类变量访问:
1、 类名.类变量名 (推荐) 静态变量的访问修饰符的访问权限和范围和普通变量是一样的。
2、 对象名.类变量名
类方法访问:
1、 类名.类方法名 (推荐) 静态变量的访问修饰符的访问权限和范围和普通变量是一样的。
2、 对象名.类方法名
举例:
类变量:
public class StaticTest {
public static void main(String[] args) {
//类名.类变量名
//类变量是随着类的加载而创建,不用创建对象也可以访问
System.out.println(A.name);
A a = new A();
//通过对象名.类变量名也可以访问
System.out.println(a.name);
}
}
class A{
//类变量也需要遵循相关的访问权限
public static String name = "你好";
//普通属性/普通成员变量/非静态属性/非静态成员变量
private int num = 10;
}
类方法:
public class Student {
public static void main(String[] args) {
//类.类方法进行调用
Stu.Pay(100);
Stu.Pay(200);
Stu.Show();
System.out.println(MyTools.calSum(10,30));
}
}
//开发自己的工具类,可以将方法做成静态的,方便调用
class MyTools{
public static double calSum(double n1, double n2){
return n1 + n2;
}
}
class Stu{
public static double totalFee = 0;
private String name;
public Stu(String name) {
this.name = name;
}
//1、方法使用static修饰时,该方法就为静态方法
//2、静态方法只能访问静态变量
public static void Pay(double fee){
Stu.totalFee += fee;
}
public static void Show(){
System.out.println("总学费为"+totalFee);
}
}
(4)注意事项和细节
-
什么时候需要用类变量
需要某个类的所有对象都共享一个变量时,就可以考虑使用类变量(静态变量)
-
类变量和实例变量(普通变量)的区别
类变量时类的所有对象共享,实例变量是每个对象共享
-
实例变量不能通过 类名.类变量名,进行访问
-
静态变量是类加载的时候,就创建了,所以不需要实例化对象,也可以访问
-
类变量的声明周期是随着类的加载开始,随着类消亡而销毁
-
静态方法(类方法)只能访问静态成员
-
类方法和普通方法都是随着类的加载而加载,将结构信息存储在方法区,类方法中无
this
参数,普通方法中隐藏着this
参数。普通方法主要不能直接通过类名.类方法进行调用 -
类方法中不允许使用和对象有关的关键字,比如
this
和super
,普通方法可以
(5)类方法与普通方法的对比
特点 | 普通方法(实例方法) | 类方法(静态方法) |
---|---|---|
关联实例 | 隶属于类的实例,通过实例化对象调用 | 不隶属于特定对象实例,直接通过类名调用 |
访问实例变量 | 可以访问和操作实例变量和实例方法,也可以访问静态方法、静态变量 | 不能直接访问实例变量或实例方法,只能访问静态方法和静态变量 |
this 、super 关键字 | 可以在方法中使用 this 关键字、super 关键字 | 不能在方法中使用 this 或 super 关键字 |
动态绑定 | 支持动态绑定,根据对象类型执行方法 | 不支持动态绑定,根据类类型执行方法 |
非静态上下文 | 在对象实例上下文中执行 | 在静态上下文中执行 |
2、理解main方法
public static void main(String[] args){}
-
main
方法是虚拟机调用的 -
java
虚拟机需要调用类的main
方法(不同类、不同包),所以该方法的访问权限必须是public
-
java
虚拟机在执行main()
方法的时候不用创建对象,所以该方法是static
-
该方法接受
String
类型的数组参数,该数组中保存执行java
命令时传递给所运行的类的参数java 执行的程序 参数1 参数2 参数3
-
main
方法中,可以直接调用main
所在类的静态方法和静态属性,但是不能使用非静态方法和属性,除非创建该类的实例对象之后,才能通过这个对象去访问类的
IDEA如果给main函数传参:
3、代码块
(1)概念
代码块是初始化块,属于类中的成员,类似于方法,将逻辑语句封装在方法体重,通过{}
包围起来。但与方法不同,没有方法名,参数和返回值,只有方法体, 不需要对象或者类显示的调用,而是加载类,或创建对象时隐式的调用。
(2)语法
[修饰符]{
代码
};
- 修饰符可选,要么不写,要么就是
static
,写了static
的代码块叫静态代码块,没有static
修饰的,叫普通代码块/非静态代码块 - 最后面的分号可写可不写。里面的代码可以是任何的逻辑语句(比如:输入、输出、方法调用,循环,判断等等)
- 相当于另外一种形式的构造器(对于构造器的补充机制),可以做初始化的操作,如果多个构造器里面都有重复的雨具,可以抽取到初始化块当中,提高代码的重用性。
(3)注意事项
-
静态代码块
(static)
,作用是对类进行初始化,随着类的加载而执行,并且 只会执行一次,如果是普通的代码块,每创建一个对象,就会执行。 -
类什么时候被加载?【重要】
- 创建对象实例时(
new
) - 创建子类对象实例,父类会被加载
- 使用类的静态成员时(静态属性、静态方法)
- 创建对象实例时(
-
普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会被调用一次。如果只是使用类的静态成员时,普通代码块并不会执行。
-
创建对象时,一个类的调用顺序【重点和难点】:
- 调用静态代码块和静态属性的位置(多个则按顺序来)
- 调用普通代码块和普通属性(多个按顺序来)
- 调用构造方法
举例:
package JavaEE.chapter08.CodeBlock; public class CodeBlockDetail02 { public static void main(String args[]){ A a = new A(); } } class A{ private int n2 = getN2(); private static int n1 = getN1(); { System.out.println("A的普通代码块"); } static { System.out.println("A的静态代码块"); } public static int getN1(){ System.out.println("getn1被调用"); return 100; } public int getN2(){ System.out.println("A普通方法被调用"); return 200; } public A(){ System.out.println("无参构造器"); } } /*输出 getn1被调用 A的静态代码块 A普通方法被调用 A的普通代码块 无参构造器 */
-
构造器的最前面隐含了
super()
和调用普通代码块,静态相关的代码块,属性初始化在类加载的时,就执行完毕了,因此是优先于构造器和普通代码块执行的。举例:
class A{ public A(){ //构造器 //隐藏的执行要求 //(1)super(); //(2)调用普通代码块 System.out.println("无参构造器"); } }
-
创建子类对象时,静态代码块,静态属性初始化,普通代码块,普通属性初始化,构造方法调用顺序:
- 父类的静态代码块和静态属性
- 子类的静态代码和静态属性
- 父类的普通代码块和普通属性
- 父类的构造方法
- 子类的普通代码块和普通属性
- 子类的构造方法
个人总结:
- 类加载(父类->子类)相关static代码执行
- 构造器
- super(父类)
- 普通代码块
- 构造方法
-
静态代码块只能调用静态成员,普通方法可以调用任意成员。
4、单例设计模式
(1)设计模式
设计模式是在大量的实践中总结和理论化之后优选的代码结构,编程风格,以及解决问题的思考方式。
(2)单例设计模式介绍
-
单例设计模式就是在整个的软件系统中,采取一定的方法保证某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法
-
实现方式
-
饿汉式(还没有用到对象,可能对象已经创建好)
- 构造器私有化
- 类的内部构造对象
- 向外暴露一个静态的公共方法返回对象
举例:
class GirlFriend { private String name; //第一步:将构造器私有化 private GirlFriend(String name){ this.name = name; } //第二步,在类的内部直接创建静态对象 private static GirlFriend gf = new GirlFriend("小红"); //第三步:提供一个公共的static方法,返回gf对象 public static GirlFriend getInstance(){ return gf; } @Override public String toString() { return "GirlFriend{" + "name='" + name + '\'' + '}'; } }
-
懒汉式(只有当用户使用
getInstance
的时候,才返回对象,再次调用时,返回是上次创建的cat对象)- 第一步:构造器私有化
- 第二步:定义一个新的
static
静态对象 - 第三步:提供一个
public
的static
方法,可以返回一个对象
举例:
//单例设计模式的懒汉式 class Cat{ private String name; public static int n1 = 999; //第一步:构造器私有化 private Cat(String name) { System.out.println("类加载。。。。"); this.name = name; } //第二步:定义一个新的static静态对象 private static Cat cat; //第三步:提供一个public的static方法,可以返回一个Ca对象 public static Cat getInstance(){ //还没有对象,就创建对象 if(cat == null){ cat = new Cat("小花喵"); } return cat; } @Override public String toString() { return "Cat{" + "name='" + name + '\'' + '}'; } }
-
(3)饿汉式和懒汉式对比
- 饿汉式是在类加载的时候就创建了对象实例,而懒汉式是在使用时才创建
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式存在浪费资源的可能,懒汉式不存在这个问题
javaSE
中,java.lang.Runtime
是一个经典的单例模式
5、FINAL 关键字
final
是 Java 中的一个关键字,它可以确保常量的值不会被修改。对于方法和类,它可以确保方法实现或类结构不会被修改或继承改变,这在某些情况下有助于代码的安全性和性能优化。
(1)final
应用场景
- 对变量使用
final
:- 当应用于变量时,
final
关键字表示该变量只能被赋值一次。一旦赋值后,就不能再更改。这适用于基本数据类型和对象引用。 - 例如:
final int x = 10;
声明了一个只能被赋值一次的整数变量x
。
- 当应用于变量时,
- 对方法使用
final
:- 当应用于方法时,
final
表示该方法不能被子类重写(覆盖)。 - 例如:
final void someMethod() { // do something }
定义了一个不能被子类重写的方法。
- 当应用于方法时,
- 对类使用
final
:- 当应用于类时,
final
表示该类不能被继承,即它是最终的,不能有子类。 - 例如:
final class MyClass { // class definition }
声明了一个不能被继承的类。
- 当应用于类时,
(2)注意事项
-
final
修饰的属性又叫做常量,一般用用XX_XX来命名(大写加下划线) -
final
修饰的属性必须赋初值,并且以后不能被修改,赋值可以有以下三个地方可以进行:- 定义,例如:
public final double TAX_RATE = 0.5;
- 构造器中
- 代码块中
- 定义,例如:
-
如果
final
修饰的属性是静态的,初始化的位置只能是:- 定义中
- 静态代码块中
-
类不是
final
类,但是含有final
方法,方法不能被重写,但是可以被继承举例:
public class FinalDetail01 { public static void main(String[] args) { BB bb = new BB(); bb.cal(); } } class AA{ final public void cal(){ System.out.println("CAL方法"); } } class BB extends AA{ }
-
一般来说,一个类已经是
final
类了,没有必要再将方法修饰成final
方法。(因为已经无法被继承了) -
final
不能修饰构造方法(即构造方法) -
final
和staic
往往搭配使用,效率更高,不会导致类加载,底层编译器做了优化处理举例:
class Demo{ public final static int n1 = 16; static { System.out.println("这里是类加载,不会被执行"); } }
-
包装类
(Integer,Double,Float,Boolean等都是final)String也是final类
。
6、抽象类
(1)介绍
当父类的一些方法不能确定时,可以用abstract
关键字来修饰该方法,这个方法就是抽象方法,用abstract
来修饰该类就是抽象类。抽象类通常用于当我们希望有一个通用的类定义,但其中的某些方法在基类中并不具备实际的实现,而是应该由具体的子类来实现。在框架和设计模式比较多
举例:
//抽象类不能被实例化,有抽象方法,这个类必须声明为abstract
abstract class AA{
//抽象方法没有方法体
public abstract void eat();
}
(2)注意事项
-
抽象类不能被实例化
-
抽象类可以没有抽象方法,但是有抽象方法的类一定是抽象类。
举例:
abstract class BB{ public void cal(){ System.out.println("抽象类可以没有抽象方法"); } }
-
抽象类只能修饰类和方法,不能修饰属性和其他的类型。
-
抽象类可以有任意成员 (抽象类本质还是类),比如:非抽象方法、构造器、静态属性等。
举例:
abstract class BB{ //属性 private String name; //构造器 public BB() { } //普通方法 public void cal(){ System.out.println("抽象类可以没有抽象方法"); } //抽象方法,没有方法体 abstract void hi(); }
-
如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为
abstract
类举例:
abstract class E{ public abstract void hi(); public abstract void sorry(); } //子类必须实现父类的所有抽象方法 class F extends E{ public void hi(){ System.out.println("hi"); } public void sorry() { System.out.println("sorry"); } }
-
抽象方法不能用
private、final和static
来修饰,因为这些关键字是与重写相违背的。
(3)抽象类实践-模版设计模式
抽象类体现的是一种模版模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展,改造,但子类总体会保留抽象类的行为模式。
可以解决的问题有:
- 当功能内部一部分是确定的,一部分是不确定的,这时可以把不确定的部分暴露出去,让子类去实现
- 编写一个抽象父类,父类提供多个子类的通用方法,并把一个活多个方法留给子类实现,这个就是模版设计模式。
举例:
abstract class Template{
public abstract void job();
//一部分抽象,一部分不抽象,可以转变为一个模板,提供给子类实现
public void calculate(){
long time = System.currentTimeMillis();
job();
long nowtime = System.currentTimeMillis();
System.out.println("该任务执行时间为:"+(nowtime-time));
}
}
class Cat extends Template{
//子类只需要负责实现抽象部分即可
public void job(){
long sum = 0;
for (int i = 0; i < 8000000; i++) {
sum += i*2;
}
}
}
class Tiger extends Template{
//子类只需要负责实现抽象部分即可
public void job(){
long sum = 0;
for (int i = 0; i < 8000000; i++) {
sum += i;
}
}
}
7、接口
(1) 基本介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类需要使用的时候,在根据具体情况把这些方法写出来
语法:
interface 接口名{
//属性
//方法
}
class 类名 implements 接口{
//自己属性
//自己方法
//必须实现的接口的抽象方法
}
//Jdk7.0之前,接口里面的所有方法都没有方法体
//Jdk8.0之后,接口中可以有方法的具体实现(默认方法、或者静态方法)
接口是更加抽象的抽象的类,Jdk8.0之后,接口类里面可以用静态方法,默认方法,可以有具体方法的实现。
举例:
interface AInterface{
public int n1 = 10;
//抽象方法
public void hi();
//使用关键字default修饰之后,可以实现具体的方法
default void ok(){
System.out.println("这里可以声明方法");
}
//使用static修饰之后,也可以实现具体的方法
static void you(){
System.out.println("这里可以声明方法");
}
}
//需要实现接口类的所有抽象方法
class A implements AInterface{
@Override
public void hi() {
System.out.println("实现接口类的抽象方法");
}
}
(2)注意事项
-
接口不能被实例化
-
接口中所有的方法都是
public
方法,接口中的抽象方法,可以不用abstract
修饰void aaa(); 实际上等同于 public abstract void aaa();
-
一个普通类实现接口,就必须将该接口的所有方法都实现。而抽象类实现接口,就可以不用实现接口的方法。
interface AInterface{ //抽象方法 public abstract void hi(); } //抽象类可以不用实现抽象方法 abstract class B implements AInterface{ }
-
一个类可以实现多个接口
interface AI{} interface BI{} class BC implements AI, BI{}
-
接口中的属性,只能是
final
,而且是public static final
修饰符,比如:int a = 1;
实际上是public static final int a = 1
(必须初始化),属性访问形式:接口名.属性名 -
接口不能继承其他的类,但是可以继承多个别的接口
interface AI{} interface BI{} interface BD extends AI,BI{}
-
接口的修饰符,只能是public或者是默认的, 这里和普通的类一样
(3)接口对比继承
接口是对行为的抽象,而继承是对类的抽象。 当子类继承了父类,就自动拥有父类的功能。如果子类需要扩展功能,可以通过实现接口的方式扩展。可以理解为接口是对单继承机制的一种补充。
- 继承的价值:解决代码的复用性和可维护性(is - a关系)
- 接口的价值:设计好各种规范(方法),让这些类去实现这些诶方法,更加的灵活。(like -a 关系)
- 接口在一定程度上可以实现代码的解耦(接口规范性+动态绑定)
(4) 接口多态
-
接口的多态
-
多态数组
以上两种举例:
public class InterfacePolyParameter { public static void main(String[] args) { //接口的多态, //接口类型的变量 if01可以指向实现了IF接口的类的对象实例 IF if01 = new Monster(); if01 = new Car(); //多态数组 IF[] if02 = new IF[2]; if02[0] = new Monster(); if02[1] = new Car(); } } interface IF{} class Monster implements IF {} class Car implements IF{}
-
接口多态传递
public class InterfacePoly {
public static void main(String[] args) {
//接口类型变量可以指向,实现该接口的类的对象实例
IG ig = new Teacher();
//IG继承了IH接口,Teacher实现了IG接口,相当于Teacher实现了IH接口,这就是接口的多态传递现象
IH ih = new Teacher();
}
}
interface IH{}
interface IG extends IH{}
class Teacher implements IG{}
8、内部类【难点和重点】
(1)基本介绍
一个类的内部有完成的嵌套了另外一个类的结构。被嵌套的类称为内部类(inner class)
,嵌套其他类的类称为外部类(outer class)
。是类的第五大成员(属性、方法、构造器、代码块、内部类),内部类的最大特点就是可以直接访问私有属性,并且可以体现类与类之间的包含关系。在很多源码当中都有大量内部类。
举例:
//类的五大成员
class Outer{//外部类
//属性
private int n1 = 100;
//构造器
public Outer(int n1) {
this.n1 = n1;
}
//方法
public void m1(){
System.out.println("方法");
}
//代码块
{
System.out.println("代码块...");
}
//内部类
class Inner{//内部类,在Outer类的内部
}
}
内部类的种类:
- 在局部位置(方法/代码块):
- 局部内部类(有类名)
- 匿名内部类(没有类名,重点)
- 成员位置:
- 成员内部类(没有
static
修饰) - 静态内部类(有
static
修饰)
- 成员内部类(没有
基本语法:
class Outer{//外部类
class Inner{//内部类
}
}
(2)局部内部类
局部内部类是定义在外部类的局部位置,比如方法或者代码块中,并且有类名
- 可以直接访问外部类的所有成员,包含私有成员
- 不能添加访问修饰符,因为这是一个局部变量,可以使用
final
,局部变量可以使用final
- 作用域:仅仅在定义它的方法或者代码块中
- 局部内部类—访问---->外部类的成员[访问方式:直接访问]
- 外部类—访问—>局部内部类的成员[访问方式:创建对象后,再访问(必须在作用域内)]
- 外部其他类—不能访问---->局部内部类
- 如果外部类与局部内部类的成员重名时,遵循就近访问原则,如果想访问外部类的成员可以使用[外部类名.this.成员]去访问
举例:
class Outer02{//外部类
private int n1 = 10;
private void m2(){}//私有方法
public void m1(){//方法
//1、局部内部类是定义在外部类的局部位置,通常实在方法里面
//3、不能添加访问修饰符,但是可以使用final修饰(不能被继承)
//4、作用域:仅仅在方法或代码块中
class Inner02{ //局部内部类(本质仍为一个类)
private int n1 = 800;
public void f1(){
//2、可以直接访问外部类的所有成员,包含私有的
//5、局部内部类可以直接访问外部类的成员,比如n1,m2()
//7、如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类的成员,可以使用 外部类名.this.成员去访问
//Outer02.this 的本质就是外部类的对象,哪个对象调用了m1,Outer02.this就是哪个对象
System.out.println("内部类n1= "+n1);
System.out.println("外部类的n1 ="+Outer02.this.n1);
m2();
}
}
//6、外部类在方法中,可以创建Inner02对象,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
注意事项:
- 局部内部类定义在方法中/代码块中
- 作用域在方法体或者代码块中
- 本质仍然是一个类
(3)匿名内部类(重要)
匿名内部类是一个没有类名的内部类。如果一个内部类的对象在一个地方只需要用一次,那么我们可以使用匿名内部类,它可以简化代码,使得代码更易于阅读。匿名内部类在编译的时候由系统自动用其父类名加$1、$2
这样的方式来命名。
匿名内部类定义在外部类的局部位置,比如方法中,并且没有类名
基本语法:
new 类或接口(参数列表){
类体
};
//参数列表会传给类的构造器
举例:
class Outer04{//外部类
private int n1 = 10;//属性
public void method(){//方法
//基于接口的匿名内部类
//1、需要A接口,并创建对象
//2、传统方法,是写一个类,实现接口,并创建对象
//3、只需要使用一次,后面不需要再使用
//4、使用匿名内部类简化开发
//5、匿名内部类tiger的运行类型为 Outer04$1,编译类型是A
//6、匿名内部类的底层实现:
/*
class Outer04$ implement A{
public void cry() {
System.out.println("老虎在叫");
}
}
*/
//7、jdk在底层创建匿名内部类Outer04$1,立马就创建了Outer04$01实例,并且把地址返回
//8、匿名内部类使用一次就不再使用
A tiger = new Tiger(){
public void cry() {
System.out.println("老虎在叫");
}
};
tiger.cry();
// A tiger = new Tiger();
// tiger.cry();
}
}
interface A{//接口
public void cry();
}
class Tiger implements A{
@Override
public void cry() {
System.out.println("老虎在叫");
}
}
注意事项:(与局部内部类类似)
- 语法比较不一样,既有定义类的特征,也有创建对象的特征。
- 可以直接访问外部类的所有成员,包含私有成员
- 不能添加访问修饰符,因为这是一个局部变量,可以使用
final
,局部变量可以使用final
- 作用域:仅仅在定义它的方法或者代码块中
- 外部其他类—不能访问---->局部内部类
- 如果外部类与局部内部类的成员重名时,遵循就近访问原则,如果想访问外部类的成员可以使用[外部类名.this.成员]去访问
实践:
public class AnonymousClassPractice {
public static void main(String[] args) {
//1、将匿名内部类直接当做实参传入函数当中
f1(new Fot() {//软编码模式
@Override
public void show() {
System.out.println("匿名内部类重写show方法");
}
});
//正常实现,比较麻烦
Example example = new Example();
f1(example);
}
public static void f1(Fot fot){
fot.show();
}
}
interface Fot{
void show();
}
//硬编码模式
class Example implements Fot{
@Override
public void show() {
System.out.println("普通类重写show方法");
}
}
(4)成员内部类
成员内部类是创建在外部类的成员位置,没有static
修饰
注意事项:
- 可以直接访问外部类的所有成员,包含私有成员
- 可以添加任意的修饰符
(public、protected、private、默认)
,可以认为这个类就是一个成员 - 作用域是和其他类的成员一样,是整个类体
- 成员内部类-----访问----->外部类成员(比如:属性)【访问方式:直接访问】
- 外部类------访问------>成员内部类【访问方式:创建对象,再访问】
- 外部其他类-----访问----->成员内部类【两种方式:外部类名.new 内部类名,或者外部类名创建一个方法返回内部类】
- 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,可以使用(外部类名.this.成员)去访问
举例:
public class MemberInnerClass {
public static void main(String[] args) {
Outer08 outer08 = new Outer08();
outer08.t1();
//外部其他类,访问成员内部类的两种种方式;
//第一种方式:把内部类当做外部类的一个成员来使用
Outer08.Inner08 inner08 = outer08.new Inner08();
inner08.say();
//第二种方式,在Outer里面创建一个方法,这个方法返回一个内部类地址
Outer08.Inner08 inner081 = outer08.getInner08Instance();
inner081.say();
}
}
class Outer08{
private int n1 = 10;
public String name = "张三";
//1、内部类是定义在外部类的成员位置
//2、可以用public、private、protected修饰
//3、作用域在整个类体
class Inner08{//成员内部类
public void say(){
//4、可以访问外部类的所有成员,包含私有的
System.out.println("n1 = "+n1 + " name = "+name);
}
}
public void t1(){
//5、外部类使用内部类,创建对象,使用他的成员即可
Inner08 inner08 = new Inner08();
inner08.say();
}
public Inner08 getInner08Instance(){
return new Inner08();
}
}
(5)静态内部类
静态内部类是定义在外部类的成员位置,并且有static
修饰,与成员内部类基本没有区别
注意事项:
- 可以直接访问外部类的所有成员,包含私有成员
- 可以添加任意的修饰符
(public、protected、private、默认)
,可以认为这个类就是一个成员 - 作用域是和其他类的成员一样,是整个类体
- 成员内部类-----访问----->外部类成员(比如:属性)【访问方式:直接访问】
- 外部类------访问------>成员内部类【访问方式:创建对象,再访问】
- 外部其他类-----访问----->成员内部类【两种方式:外部类名.new 内部类名,或者外部类名创建一个方法返回内部类】
- 如果外部类和内部类的成员重名时,内部类访问遵循就近原则,如果想访问外部类的成员,可以使用(外部类名.成员)去访问 【不需要加this】