Java面向对象编程-高级
目录
main方法
解释main方法的形式: public static void main(String[] args){}
- main方法时虚拟机调用
- java虚拟机需要调用类的main()方法,所以该方法的访问权限必须是public
- java虚拟机在执行main()方法时不必创建对象,所以该方法必须是static
- 该方法接收String类型的数组参数,该数组中保存执行java命令时传递给所运行的类的参数,案例演示,接收参数
- java执行的程序参数1参数2参数…
类变量
基本介绍
语法:访问修饰符 static 数据类型 变量名;
类变量也叫静态变量/静态属性,是该类的所有对象共享的变量,任何一个该类的对象去访问它时,取到的都是相同的值,同样任何一个该类的对象去修改它时,修改的也是同一个变量。
类变量可以通过类名访问,也可以通过对象访问。
示例:
public class ChildGame {
public static void main(String[] args) {
int count = 0;
Child child1 = new Child("白骨精");
child1.join();
child1.count++;
Child child2 = new Child("狐狸精");
child2.join();
child2.count++;
Child child3 = new Child("老鼠精");
child3.join();
child3.count++;
//===========
System.out.println("共有" + Child.count + " 小孩加入了游戏...");
System.out.println("child1.count=" + child1.count);//3
System.out.println("child2.count=" + child2.count);//3
System.out.println("child3.count=" + child3.count);//3
}
}
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 + " 加入了游戏..");
}
}
使用细节
- 什么时候使用类变量:当我们需要让某个类的所有对象都共享一个变量时候。
- 类变量和实例变量的区别:类变量由该类的所有对象共享,而实例变量是每个对象独享。
- 类变量在类加载时候就进行了初始化,如果没有指定初始值将执行默认初始化。如果使用方法的返回值初始化,只能使用静态方法。
- 类变量的声明周期是随着类的加载开始,随着类消亡而销毁。
类方法
基本介绍
语法:访问修饰符 static 数据返回类型 方法名(){}
在Java中,类方法是一种属于类类型的方法,可以使用类名访问,也可以使用对象名访问,方法体中,可以访问类变量,但不能直接访问实例变量。
使用场景:
当方法中不涉及到任何和对象相关的成员,则可以将方法设计成静态方法, 提高开发效率。比如:
工具类中的方法utils。Math类、Arrays类、Collections集合类看下源码可以发现都是static方法。
使用细节
- 类方法和普通方法都是随着类的加载而加载。将结构信息存储在方法区:类方法中无this参数,普通方法中含有this参数。
- 类方法可以通过类名调用,也可以通过对象名调用。普通方法和对象有关,需要通过对象名调用。
- 类方法中不允许使用和对象有关的的关键字,比如this和super。
- 类方法中只能访问静态变量和静态方法。普通方法可以访问非静态成员,也可以访问静态成员。
代码块
基本介绍
java中,用{}括起来的称为代码块,可以分为一下四种:
- 普通代码块:类中方法的方法体
- 构造代码块:构造块会在每次创建对象时被调用,优先于类构造函数执行。
- 静态代码块:用static{}包裹起来的代码片段。只在加载对象时候,执行一次。如果是创建对象时候,静态代码块优先于构造块执行。
- 同步代码块:使用synchronized(){}包裹起来的代码块,在多线程环境下,对共享数据的读写操作是需要互斥进行的,否则会导致数据的不一致性。同步代码块需要写在方法中。
构造/静态代码块
语法:
[修饰符]{
代码
};
注意:要么没有修饰符,要么修饰符为static.
使用代码块的好处:
- 对构造器的一种补充机制,可以做初始化等操作。
- 场景:如果多个构造器中都有重复的语句,可以抽取到初始化块中,提高代码的重用性。
示例:
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;
{
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;
}
}
使用细节
构造器中:
public A() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化...
System.out.println("A的构造器");
}
- static代码块也叫静态代码块,作用就是对类进行初始化,而且它随着类的加载而执行,并且只会执行一次。如果是普通代码块,每创建一个对象, 就执行一次。
- 类什么时候被加载
- 创建对象实例时(new)
- 创建子类对象实例,父类也会被加载
- 使用类的静态成员时(静态属性,静态方法)
- 普通的代码块,在创建对象实例时,会被隐式的调用。被创建一次,就会调用一次。
- 如果只是使用类的静态成员时,普通代码块并不会执行。(没有创建对象实例)
- 创建一个对象时,在一个类调用顺序是 (重点,难点) ∶
- 调用静态代码块和静态属性初始化 (注意:静态代码块和静态属性初始化调用的优先级一样,如果有多个静态代码块和多个静态变量初始化,则按他们定义的先后顺序调用)
- 调用普通代码块和普通属性的初始化(注意:普通代码块和普通属性初始化调用的优先级一样,如果有多个普通代码块和多个普通属性初始化,则按定义先后顺序调用)
- 调用构造方法
- 构造器的最前面其实隐含了super()和调用普通代码块, 静态相关的代码块,属性初始化,在类加载时,就执行完毕,因此是优先于构造器和普通代码块执行的。
- 我们看一下创建一个子类对象时(继承关系),他们的调用顺序如下:
- 父类的静态代码块和静态属性(优先级一样,按定义顺序执行)(类加载)
- 子类的静态代码块和静态属性(优先级一样,按定义顺序执行)(类加载)
- 父类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 父类的构造方法
- 子类的普通代码块和普通属性初始化(优先级一样,按定义顺序执行)
- 子类的构造方法
- 静态代码块(本质上是静态方法)只能直接调用静态成员(静态属性和静态方法),普通代码块(本质上是普通方法)可以调用任意成员。
package com.hspedu.codeblock_;
public class CodeBlockDetail04 {
public static void main(String[] args) {
//老师说明
//(1) 进行类的加载
//1.1 先加载 父类 A02 1.2 再加载 B02
//(2) 创建对象
//2.1 从子类的构造器开始
B02 b02 = new B02();//对象
System.out.println("===========================");
new B02();
// new C02();
}
}
class A02 { //父类
private static int n1 = getVal01();
//static B02 b02 = new B02();
static {
System.out.println("B02.n3 "+B02.n3);
System.out.println("A02的一个静态代码块..");//(2)
}
{
System.out.println("A02的第一个普通代码块..");//(5)
}
public int n2 = getVal02();//普通属性的初始化
public static int getVal01() {
System.out.println("A02静态属性n1初始化 getVal01");//(1)
return 10;
}
public int getVal02() {
System.out.println("A02成员属性n2初始化 getVal02");//(6)
return 10;
}
public A02() {//构造器
//隐藏
//super()
//普通代码和普通属性的初始化......
System.out.println("A02的构造器");//(7)
}
}
class B02 extends A02 { //
static int n3 = getVal03();
static {
System.out.println("B02的一个静态代码块..");//(4)
}
public int n4 = getVal04();
{
System.out.println("B02的第一个普通代码块..");//(9)
}
public static int getVal03() {
System.out.println("B02静态属性n3初始化 getVal03");//(3)
return 10;
}
public int getVal04() {
System.out.println("B02成员属性n4初始化 getVal04");//(8)
return 10;
}
//一定要慢慢的去品..
public B02() {//构造器
//隐藏了
//super()
//普通代码块和普通属性的初始化...
System.out.println("B02的构造器");//(10)
// TODO Auto-generated constructor stub
}
}
运行结果
A02静态属性n1初始化 getVal01
B02.n3 0
A02的一个静态代码块..
B02静态属性n3初始化 getVal03
B02的一个静态代码块..
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
===========================
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
加上static B02 b02 = new B02();
A02静态属性n1初始化 getVal01
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
B02.n3 0
A02的一个静态代码块..
B02静态属性n3初始化 getVal03
B02的一个静态代码块..
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
===========================
A02的第一个普通代码块..
A02成员属性n2初始化 getVal02
A02的构造器
B02成员属性n4初始化 getVal04
B02的第一个普通代码块..
B02的构造器
注意:对于静态成员属性,在赋初值前,都会被默认初始化,其中引用类型会赋予null。
final关键字
基本介绍
final可以修饰类、属性、方法和局部变量。
使用场景:
- 当不希望类被继承时。
- 当不希望父类的某个方法被子类覆盖/重写(override)时。
- 当不希望类的的某个属性的值被修改时。(例如: public final double TAX RATE=0.08)
- 当不希望某个局部变量被修改,可以使用final修饰(例如: final double TAX RATE=0.08),大写。
final修饰变量
- final修饰的属性又叫常量,一般用 XX_XX_XX (大写)来命名。
- final修饰的属性在定义时,必须赋初值,并且以后不能再修改:
- 定义的时候
- 在构造器中
- 在代码块中
class AA {
public final double TAX_RATE2 ;
public final double TAX_RATE3 ;
public AA() {//构造器中赋值
System.out.println("执行构造函数");
TAX_RATE2 = 1.1;
}
{//在代码块赋值
System.out.println("执行代码块");
TAX_RATE3 = 8.8;
}
public double getValue(){
System.out.println("执行getValue");
return 0.08;
}
public final double TAX_RATE = getValue();//定义时赋值
}
执行结果:
执行代码块
执行getValue
执行构造函数
注意:如果final修饰的属性是静态的,则初始化的位置只能是1. 定义时(或调用静态函数)2.在静态代码块(不能在构造器中赋值,因为构造器是在对象创建的时候才会进行赋值)
final修饰类/方法
将方法和类声明成final只有一个原因:确保他们不会在子类中改变语义(结合多态理解),有些人认为:除非由足够多的理由使用多态,否则应该将所有的方法声明成final。
- 一般来说,如果一个类已经是final类了,就没有必要再将方法修饰成final方法。(因为类既然不能被继承,也就相应无法被重写)。
- final不能修饰构造方法。
- final和static 往往搭配使用,效率更高,因为不会导致类加载,底层编译器做了优化处理。
抽象类
当父类的某些方法,需要声明,但是又不确定如何实现时,可以将其声明为抽象方法,那么这个类就是抽象类。
- 用abstruct关键字来修饰一个类时,这个类就叫抽象类。
- 用abstruct关键字来修饰一个方法时,这个方法就是抽象方法。
访问修饰符 abstract 返回类型 方法名(参数列表);//没有方法体
注意:
- 抽象类不能被实例化。
- 抽象类不一定包含abstruct方法,也就是说,抽象类可以没有abstruct方法。
- 一旦类包含了abstract方法,则这个类必须声明为abstract。
- abstract只能修饰类和方法,不能修饰属性和其它的。
- 抽象类可以有任意成员【抽象类本质还是类】,比如: 非抽象方法、构造器、静态属性等等。
- 如果一个类继承了抽象类,则它必须实现抽象类的所有抽象方法,除非它自己也声明为abstract类。
- 抽象方法不能使用private、final和 static来修饰,因为这些关键字都是和重写相违背的。
模板设计模式
package com.hspedu.abstract_.template;
abstract public class Template { //抽象类-模板设计模式
private String name;
public Template(String name) {
this.name = name;
}
public abstract void job();//抽象方法
public abstract String getName();
public void calculateTime() {//实现方法,调用job方法
//得到开始的时间
long start = System.currentTimeMillis();
job(); //动态绑定机制
//得的结束的时间
long end = System.currentTimeMillis();
System.out.println(getName()+"任务执行时间 " + (end - start));
}
}
接口
基本介绍
接口就是给出一些没有实现的方法,封装到一起,到某个类要使用的时候,在根据具体情况把这些方法写出来。
接口是更加抽象的类。抽象类里的方法可以有方法体,接口里的所有方法都没有方法体(jdk7),接口体现了程序设计的多态和高内聚低偶合的设计思想。
示例:
public interface DBInterface { //项目经理
String name = "usb";
void connect();//连接方法
void close();//关闭连接
}
public class OracleDB implements DBInterface{
@Override
public void connect() {
System.out.println("连接oracle");
}
@Override
public void close() {
System.out.println("关闭oracle");
}
}
public class Interface03 {
public static void main(String[] args) {
MysqlDB mysqlDB = new MysqlDB();
t(mysqlDB);
OracleDB oracleDB = new OracleDB();
t(oracleDB);
}
public static void t(DBInterface db) {
System.out.println(UsbInterface.name);
db.connect();
db.close();
}
}
使用细节
- 接口不能被实例化。
- 接口中所有的方法默认是public和abstruct方法,实现该方法不写public会报错。
- 一个普通类实现接口,必须实现所有方法;一个抽象类实现接口,可以不实现方法。
- 接口是java继承机制的补充,一个类可以实现多个接口。
- 接口不能继承其它类,一个接口可以继承多个接口。
- 与类一致,接口的修饰符只有public和默认。
- 接口中的属性,默认使用public static final修饰符,使用接口名.属性名访问。
继承和接口对比
当子类继承了父类,就自动的拥有父类的功能,如果子类需要扩展功能,可以通过实现接口的方式扩展。
接口是对java单继承机制的一种补充,继承和接口解决的问题不同:
- 继承的价值在于:解决代码的复用性和可维护性。
- 接口的价值在于:设计好各种规范方法,让其它类实现这些方法。
- 接口比继承更加灵活:继承满足is-a的关系,而接口满足has-a的关系。
接口的多态
定义接口
public interface UsbInterface { //接口
//规定接口的相关方法,老师规定的.即规范...
void start();
void stop();
}
public class Camera implements UsbInterface {//实现接口,就是把接口方法实现
public void work(){
System.out.println("相机正在拍照");
}
@Override
public void start() {
System.out.println("相机开始工作...");
}
@Override
public void stop() {
System.out.println("相机停止工作....");
}
}
public class Phone implements UsbInterface {
public void call(){
System.out.println("手机正在打电话");
}
@Override
public void start() {
System.out.println("手机开始工作...");
}
@Override
public void stop() {
System.out.println("手机停止工作.....");
}
}
public static void main(String[] args) {
UsbInterface[] usbs = new UsbInterface[2];
usbs[0] = new Camera();
usbs[1] = new Phone();
work(usbs);
}
public static void work(UsbInterface[] usbs) {
for (UsbInterface usb : usbs) {
usb.start();
if(usb instanceof Camera){
((Camera)usb).work();
} else if (usb instanceof Phone) {
((Phone)usb).call();
}
usb.stop();
}
}
内部类
一个类的内部又完整地嵌套了另一个类地结构,被嵌套的类称为内部类,嵌套类的类称为外部类。
类的五大成员:字段(属性)、方法、构造器、代码块、内部类。内部类可以直接访问私有属性。
内部类分类
定义在外部类局部位置上(比如方法内):
- 局部内部类
- 匿名内部类
定义在外部类成员位置上:
- 成员内部类
- 静态内部类
局部内部类
- 不能添加访问修饰符,但是可以使用final修饰,因为局部变量也可以使用final修饰。
- 内部类中:直接访问外部类所有成员,包含私有成员。如果外部类成员名(属性和方法)与局部内部类的成员名重名,按照就近原则,同时,可以使用
外部类名.this.成员
访问。 - 方法体中:首先创建对象,可以访问局部内部类中的所有属性和方法,包括私有成员。
如果内部类继承了其它类,只能根据继承体系中访问修饰符访问父类的成员。(作用域从里到外:子类,父类,类外)
public class LocalInnerClass_ {
public static void main(String[] args) {
Outer01_ outer01 = new Outer01_();
outer01.f1();
}
}
class Outer01_ {
private int num = 10;
private int num2 = 20;
public void f1() {
class Inner01 extends Outer011_{
private int num = 10;
protected int num2 = 20;
public int num3 = 40;
int num4 = 50;
public void f1() {
super.f1();
System.out.println("外部类属性num:" + Outer01_.this.num + " 外部类属性num2:" + num2 + " 内部类属性num:" + num);
Outer01_.this.f2(); // f2();
f3();
}
public void f2() {
System.out.println("内部类f2");
}
}
Inner01 inner01 = new Inner01();
inner01.f1();
inner01.f3();//父类而非类外
// inner01.f4();
System.out.println(inner01.num+inner01.num2+inner01.num3+inner01.num4);
System.out.println(/*inner01.sal+*/inner01.sal2+inner01.sal3+inner01.sal4);
}
public void f2() {
System.out.println("外部类f2");
}
public void f3(){
System.out.println("外部类f3");
}
}
class Outer011_{
private int sal = 100;
protected int sal2 = 200;
public int sal3 = 300;
int sal4 = 400;
public void f1(){
System.out.println("Outer011_ f1");
}
public void f2(){
System.out.println("Outer011_ f2");
}
public void f3(){
System.out.println("Outer011_ f3");
}
private void f4(){
System.out.println("Outer011_ f4");
}
}
Outer011_ f1
外部类属性num:10 外部类属性num2:20 内部类属性num:10
外部类f2
Outer011_ f3
Outer011_ f3
120
900
匿名内部类
匿名内部类定义在方法体,匿名内部类既是一个类的定义,同时本身也是一个对象。
- 没有访问修饰符,继承某个对象,直接定义。
- 内部类中:直接访问外部类所有成员,包含私有成员。如果外部类成员名(属性和方法)与局部内部类的成员名重名,按照就近原则,同时,可以使用
外部类名.this.成员
访问。 - 方法体中:只能根据访问修饰符访问其静态类型中的成员。
public class AnonymousInnerClassDetail_ {
public static void main(String[] args) {
Outer03_ outer03 = new Outer03_();
outer03.f1();
}
}
class Outer03_{
private int num=10;
public int num2 =20;
public void f1(){
Person_ person = new Person_(){
private int num =10;
public int num2 = 20;
protected int num3 = 30;
int num4 =40;
public void f1() {
System.out.println("外部类属性num:" + Outer03_.this.num + " 外部类属性num2:" + num2 + " 匿名内部类属性num:" + num);
Outer03_.this.f2();
f2();
}
public void f2(){
System.out.println("内部类f2");
}
@Override
public void hi() {
f1();
System.out.println("匿名内部类 人在打招呼");
}
};
person.hi();
person.work();
// System.out.println(person.num+person.num2+person.num3+person.num4);
System.out.println(/*person.sal+*/person.sal2+person.sal3+person.sal4);
// person.f1(); //这里报错 这里可以使用静态类型理解
}
public void f2() {
System.out.println("外部类f2");
}
}
class Person_{
private int sal = 100;
protected int sal2 = 200;
public int sal3 = 300;
int sal4 = 400;
public void hi() {
System.out.println("Person hi()");
}
public void work(){
System.out.println("人在工作");
}
}
外部类属性num:10 外部类属性num2:20 匿名内部类属性num:10
外部类f2
内部类f2
匿名内部类 人在打招呼
人在工作
900
匿名内部类最佳实现
public class AnonymousInnerClass_ {
public static void main(String[] args) {
Outer02_ outer02 = new Outer02_();
outer02.f1();
outer02.f2(new IA_() {
@Override
public void cry() {
System.out.println("匿名内部类直接传参");
}
});
}
}
class Outer02_ {
private int n = 10;
public void f1(){
IA_ dog = new IA_() {
@Override
public void cry() {
System.out.println("小狗汪汪叫");
}
};
System.out.println("匿名内部类,tiger的运行类型=" + dog.getClass());
dog.cry();
}
public void f2(IA_ ia){
ia.cry();
}
}
interface IA_ {
void cry();
}
匿名内部类,tiger的运行类型=class com.hspedu.innerclass.Outer02_$1
小狗汪汪叫
匿名内部类直接传参
成员内部类
- 可以添加访问修饰符,这里本质是一个成员。
- 直接访问外部类所有成员,包含私有成员。外部类成员名(属性和方法)与成员内部类的成员名重名,按照就近原则,同时,可以使用
外部类名.this.成员
访问。 - 外部类:创建对象,再访问。可以访问成员内部类中的所有属性和方法,包括私有成员。
- 其它外部类:得到成员内部类对象,只能根据访问修饰符访问对应成员(这时候成员内部类不能是private)。
public class MemberInnerClass01_ {
public static void main(String[] args) {
Outer04_ outer04 = new Outer04_();
//1 方法中使用
outer04.t1();
System.out.println("===================");
//2 返回对象
Outer04_.Inner instance = outer04.getInstance();
instance.f1();
System.out.println("===================");
//3 外部调用
Outer04_.Inner inner = outer04.new Inner();
inner.f1();
System.out.println("===================");
System.out.println(/*inner.num+*/inner.sal+inner.sal2+inner.sal3); // 除了private其它可以访问
}
}
class Outer04_ {
private int num = 10;
public int num2 = 20;
public String name = "张三";
public class Inner {
private int num = 30;
public double sal =40.0;
protected double sal2 = 50.0;
double sal3 = 60.0;
public void f1() {
System.out.println("外部类属性num:" + Outer04_.this.num + " 外部类属性num2:" + num2 + " 成员内部类属性num:" + num);
}
}
private void f1(){
System.out.println("外部类f1");
}
public Inner getInstance(){
return new Inner();
}
public void t1(){
Inner inner = new Inner();
inner.f1();
System.out.println(inner.num+inner.sal+inner.sal2+inner.sal3); // 内部类中所有元素都可以访问
}
}
外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
180.0
===================
外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
===================
外部类属性num:10 外部类属性num2:20 成员内部类属性num:30
===================
150.0
注意:如果有private修饰,那么在类外,无法访问成员内部类的所有成员。
静态内部类
静态内部类是定义在外部类的成员位置, 并且有static修饰。
- 可以添加访问修饰符,这里本质是一个静态成员,在类加载时进行初始化。
- 直接访问外部类所有静态成员,包括私有成员,不能访问非静态成员。外部类成员名(属性和方法)与静态成员内部类的成员名重名,按照就近原则,同时可以使用
外部类名.成员
访问。 - 外部类:创建对象,再访问。可以访问静态成员内部类中的所有成员,包括私有成员。
- 其它外部类:创建对象,再访问。得到静态成员内部类对象,只能根据访问修饰符访问对应成员(这时候成员内部类不能是private)。
public class StaticInnerClass01_ {
public static void main(String[] args) {
Outer05_ outer05 = new Outer05_();
//1 方法中使用
outer05.t1();
System.out.println("===================");
//2 非静态方法返回对象
Outer05_.Inner instance = outer05.getInstance();
instance.f1();
System.out.println("===================");
//3 静态方法返回对象
Outer05_.Inner instance2 = Outer05_.getInstance2();
instance2.f1();
System.out.println("===================");
//4 外部创建
Outer05_.Inner inner = new Outer05_.Inner();
inner.f1();
System.out.println("===================");
//System.out.println(inner.num);
System.out.println(inner.sal);
}
}
class Outer05_ {
private static int num = 10;
public static int num2 = 20;
public String name = "张三";
public static class Inner {
public static int num2=getNum2();
private int num = 30;
public double sal =40.0;
protected double sal2 = 50.0;
double sal3 = 60.0;
public void f1() {
System.out.println(num);//可以访问静态成员
//System.out.println(name);//不可以访问非静态成员
System.out.println("外部类属性num:" + Outer05_.num + " 外部类属性num2:" + num2 + " 静态内部类属性num:" + num);
}
public static int getNum2(){
System.out.println("静态成员初始化");
return 10;
}
static {
System.out.println("静态成员内部类静态代码块");
}
}
private void f1(){
System.out.println("外部类f1");
}
public Inner getInstance(){
Inner inner = new Inner();
System.out.println(inner.hashCode());
return inner;
}
public static Inner getInstance2(){
Inner inner = new Inner();
System.out.println(inner.hashCode());
return inner;
}
public void t1(){
Inner inner = new Inner();
inner.f1();
System.out.println(inner.num+inner.sal+inner.sal2+inner.sal3); // 内部类中所有元素都可以访问
}
}
静态成员初始化
静态成员内部类静态代码块
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
180.0
===================
460141958
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
1163157884
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
外部类属性num:10 外部类属性num2:10 静态内部类属性num:30
===================
40.0