静态、动态、动态入参匹配、static静态和非静态、初始化块
※静态入参匹配
–根据入参变量的编译时类型决定调用哪个方法
(谁入参到这个方法就根据谁的编译时类型来决定)
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
public class Test01 {
//定义方法
public void test(A a) {
System.out.println("test-------------A");
}
public void test(B b) {
System.out.println("test-------------B");
}
public void test(C c) {
System.out.println("test-------------C");
}
public static void main(String[] args) {
//创建实例对象
Test03 test03 = new Test03();
//操作一:
A a = new A();
B b = new B();
//
test03.test(a);//test-------------A
test03.test(b);//test-------------B
//操作二:
A a1 = new B();
B b1 = new C();
A a_b = b1;
//(没有多态时):在确认同一个类时,根据方法签名【入参的变量的编译时类型】决定
//根据方法签名
test03.test(a1);//test-------------A
test03.test(b1);//test-------------B
test03.test(a_b);//test-------------A
}
}
// A --> B --> C
class A{
}
class B extends A{
}
class C extends B{
}
※动态入参匹配
–根据调用方法的引用变量的运行时类型决定调用哪个类
(谁调用了这个方法就根据谁的运行时类型来决定)
1、确定调用哪个类【调用方法的变量的运行时类型确定】
2、确定调用哪个方法【入参的变量的编译时类型确定】
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
package com.g0714work;
public class Test02 {
public static void main(String[] args) {
// //操作一:
// A a = new A();
// B b = new B();
// C c = new C();
//
// //输出结果:
// a.test(c);//A----c
// b.test(a);//B----a
// 操作二:
// 1、确定调用哪个类【调用方法的变量的运行时类型确定】
// 2、确定调用哪个方法【入参的变量的编译时类型确定】
A a = new A();
B b = new B();
A a_c = new C();
A a_b = b;
// 输出结果:
a_c.test(b);// C-------------b
// 简单来说就是先确认运行时类型的就是new C();C类型,
// 然后再确认编译时类型为B b,为b
a_b.test(a);// B-------------a
// 先确认运行时类型的就是new B();B类型,
// 然后再确认编译时类型为A a,为a
// 操作三:
C cc = (C) a_c;
cc.test(a_b);// C------------a
// 先确认运行时类型的就是new C();C类型,
// 然后再确认编译时类型为A a_b,为a
}
}
// A --> B --> C
class A {
// 定义方法
public void test(A a) {
System.out.println("A-------------a");
}
public void test(B b) {
System.out.println("A-------------b");
}
public void test(C c) {
System.out.println("A-------------c");
}
}
class B extends A {
// 定义方法
public void test(A a) {
System.out.println("B-------------a");
}
public void test(B b) {
System.out.println("B-------------b");
}
public void test(C c) {
System.out.println("B-------------c");
}
}
class C extends B {
// 定义方法
public void test(A a) {
System.out.println("C-------------a");
}
public void test(B b) {
System.out.println("C-------------b");
}
public void test(C c) {
System.out.println("C-------------c");
}
}
※动态入参匹配plus
// 方法调用在编译的时候已经确定了,如果运行时类型有重写方法则显示子类特征
–// 1、先编译【test(A a)】,后运行【test(A a)】(看得见和看不见的问题)
–// 2、确定调用在哪个类中的方法【根据引用变量的运行时类型】
–// 3、确定调用在哪个方法【根据引用变量的编译时类型】
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
public class Test03 {
public static void main(String[] args) {
// 操作一:
A a = new B();
B b = new B();
// 方法调用在编译的时候已经确认了,如果运行时类型有重写方法则显示子类特征
// 编译的时候已经确定了类型了,运行的时候是确认有没有进行方法重写
// 1、先编译【test(A a)】,后运行【test(A a)】
// 2、确定调用哪个类【调用方法的变量的运行时类型确定】
// 3、确定调用哪个方法【入参的变量的编译时类型确定】
// 注意:这里是还没有在classA中加入方法的 以下方法是操作二才加入的
// public void test(B b) {
// System.out.println("A-------------b");
// }
a.test(b);// B------------a
// //操作二:
// A a = new B();
// B b = new B();
// a.test(b);// B------------b
}
}
// A --> B --> C
class A {
// 定义方法
public void test(A a) {
System.out.println("A-------------a");
}
public void test(B b) {
System.out.println("A-------------b");
}
}
class B extends A {
// 定义方法
public void test(A a) {
System.out.println("B-------------a");
}
public void test(B b) {
System.out.println("B-------------b");
}
}
※static静态的和非静态的区别
表示的静态的意思,属于类的,当使用到这个类的时候会静态加载静态的属性以及方法。
–static用于修饰变量和方法、代码块
–有static修饰的则为静态的,没有的则为非静态
–静态的是属于类的 静态的东西是每个对象都共享的【同一个内存区域】
–而非静态是属于对象的,每个对象都有一个独立的内存空间【互不干涉】
–静态方法可以通过类名直接访问
–非静态的属性和方法要通过对象访问访问
–非静态代码块可以直接访问当前类中的非静态方法和属性
–静态的代码块中,不能直接访问非静态的方法和属性,除非通过对象调用
思考:什么时候使用静态,什么时候使用非静态
工具方法、常量使用静态修饰,同一个类中共享的可以静态
定义类时的成员方法以及属性一般就是非静态修饰
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
public class Person {
private String name;
private String sex;
private int age;
public static void main(String[] args) {
// 创建两个新的对象
Person p1 = new Person("zhang", "nan", 26);
Person p2 = new Person("li", "nan", 18);
// 输出p1和p2的值
System.out.println(p1);// Person [name=zhang, sex=nan, age=26]
System.out.println(p2);// Person [name=li, sex=nan, age=18]
// 给静态变量赋值
// 操作二:
// 静态的属性和方法在类加载的时候已经在方法区中分配了内存
p1.item = 15;
System.out.println(p1.item);// 15
System.out.println(p2.item);// 15
// 操作四:
// static的方法、变量可以直接使用类名来调用
System.out.println(Person.item);
// 调用静态的方法
p1.test();
}
// static使用的注意事项:
// static用于修饰变量、方法、类
// static静态的是属于类的,非静态是属于对象的【静态与非静态的区别】
// static的方法、变量可以直接使用类名来调用
// static修饰的变量--当前的类变量
// 静态的代码块不能直接调用非静态的属性及方法,除非通过对象调用【内存的分配】
// 静态的属性和方法在类加载的时候已经在方法区中分配了内存
// 操作一:
// 定义一个静态变量
public static int item = 10;
// 操作三:
// 定义一个静态的测试方法
public static void test() {
// Cannot make a static reference to the non-static field name
// 意思就是:静态的方法中不能调用非静态的引用
// 静态的代码块不能直接调用非静态的属性及方法,除非通过对象调用【内存的分配】
// System.out.println(name);
// System.out.println(getName());
// 解决办法:
// 需要创建一个新的对象来进行调用
Person p = new Person();
System.out.println(p.name);
System.out.println(p.getName());
}
// 非静态的方法
// 可以直接调用
public void test1() {
System.out.println(name);
System.out.println(getName());
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Person() {
super();
}
public Person(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
– 操作二:
初始化以及初始化块(静态与非静态)以及在继承链中的顺序
【了解即可】
-
-初始化块的作用是用于在类加载或者创建对象时,可以设置一些固定的初始化操作(初始化成员变量、执行其他类的加载)
-
-静态初始化块只执行一次(类加载时),非静态初始化块每创建一个对象就执行一次
-
-静态初始化块–>非静态初始化块–>构造器
// 总结:
// 构造器(全参、有参、无参)–>非静态代码块(代码块)–>静态代码块
// 静态初始化块,只会执行一次【类加载–加载其他库】
// 每创建一个对象,非静态初始化块都会执行一次
// 定义一个非静态初始化代码块,对象数据进行初始化值
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
public class Test {
public static void main(String[] args) {
// 操作一:
// 添加了无参构造器、全参构造器和toString方法
// Person p = new Person();
// System.out.println(p);//Person [name=null, sex=null, age=0]
// 操作二:
// 加上了一个初始化块 添加了无参构造器、全参构造器和toString方法
// Person p = new Person();
// System.out.println(p);//Person [name=无名氏, sex=男, age=10]
// // 操作三:
// 加上了一个初始化块 并给对象赋值 添加了无参构造器、全参构造器和toString方法
// 这里就算不要初始化块还是会给输出对象数据
// Person p = new Person("zhang", "nan", 19);
// System.out.println(p);
// Person [name=zhang, sex=nan, age=19]
// 操作四:
// 加上了一个初始化块 并添加一个输出语句"初始化块执行" 并给对象赋值 添加了无参构造器、全参构造器和toString方法
// Person p = new Person("zhang", "nan", 19);
// System.out.println(p);
// 初始化块执行
// Person [name=zhang, sex=nan, age=19]
// 操作五:
// 加上了一个初始化块 并添加一个输出语句"初始化块执行" 并给对象赋值 添加了无参构造器、全参构造器和toString方法
// 并且分别给构造器添加上"全参构造器初始化块执行"和"无参构造器初始化块执行"
// 就算注释了全参构造器和初始化,无参构造器还是不会输出语句,因为没有对它进行调用
// 要是要实现无参构造器的调用还是需要不对对象进行赋值
// Person p = new Person("zhang", "nan", 19);
// System.out.println(p);
// 初始化块执行
// 全参构造器初始化块执行
// Person [name=null, sex=null, age=0]
// 操作六:
// 加上了一个初始化块 并添加一个输出语句"初始化块执行"
// 添加了无参构造器、全参构造器和toString方法
// 并且分别给构造器添加上"全参构造器初始化块执行"和"无参构造器初始化块执行"
// 没有给对象进行赋值
// Person p = new Person();
// System.out.println(p);
// 初始化块执行
// 无参构造器初始化块执行
// Person [name=无名氏, sex=男, age=10]
// 操作七:
// 加上了一个静态初始化块并加上输出语句"静态初始化块执行"
// 加上了一个非静态初始化块并添加一个输出语句"非静态初始化块执行"
// 添加了无参构造器、全参构造器和toString方法
// 并且分别给构造器添加上"全参构造器初始化块执行"和"无参构造器初始化块执行"
// Person p = new Person("zhang", "nan", 19);
// System.out.println(p);
// 静态初始化块执行
// 非静态代码块初始化块执行
// 全参构造器初始化块执行
// 总结:
// 构造器(全参、有参、无参)-->非静态代码块(代码块)-->静态代码块
// 静态初始化块,只会执行一次【类加载--加载其他库】
// 每创建一个对象,非静态初始化块都会执行一次
// 定义一个非静态初始化代码块,对象数据进行初始化值
}
}
/**
* @author Lantzrung
* @date 2022年7月21日
* @Description
*/
public class Person {
public String name ;
public String sex;
public int age;
//定义一个静态变量
public static int item;
//静态初始化块,只会执行一次【类加载】
static {
//赋值给变量
item = 15;
System.out.println("静态初始化块执行");
}
// 每创建一个对象,非静态初始化块都会执行一次
// 定义一个非静态初始化代码块,对象数据进行初始化值
{
name = "无名氏";
sex = "男";
age = 10;
System.out.println("初始化块执行");
}
//操作二:定义初始化块,对对象数据进行初始化约定
public Person(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
System.out.println("全参构造器初始化块执行");
}
public Person() {
super();
System.out.println("无参构造器初始化块执行");
}
@Override
public String toString() {
return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
}
}
增加一个细节:
/**
* @author Lantzrung
* @date 2022年7月21日
* @Description
*/
public class Person {
//定义一个静态变量
//静态初始化块,只会执行一次【类加载】
public static int item = 20;//静态变量
public final static int item2 = 10;//静态常量 注意:颜色比常量变得更深一点
static {
//赋值给变量
item = 15;
System.out.println("静态初始化块执行");
}
}
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
public class Test01 {
public static void main(String[] args) {
// 操作一:
// 静态变量在静态代码块前的时候,输出的是静态代码块中的变量数据
// Person p = new Person();
// System.out.println(p.item);//15
// 操作二:
// 静态变量在静态代码块后的时候,输出的是静态变量的数据
Person p = new Person();
System.out.println(p.item);// 20
}
}
初始化块在继承链的顺序
思考:如果初始化块在继承链中,又是怎么样?
总结:父类静态初始化块(父类的静态变量)–>子类静态初始化块(子类的静态变量)–>父类非静态初始化块–>父类构造器–>子类非静态初始化块–>子类构造器
/**
* @author Lantzrung
* @date 2022年7月22日
* @Description
*/
package com.g0714work.copy;
public class Test02 {
public static void main(String[] args) {
Student p = new Student("zhang", "nan", 18);
System.out.println(p);
// Person静态初始化块执行
// Student静态初始化块执行
// Person非静态初始化块执行
// Person全参构造器初始化块执行
// Student非静态初始化块执行
// Student全参构造器初始化块执行
// 总结:子类构造器-->子类非静态初始化块-->父类构造器-->父类非静态初始化块-->子类静态初始化-->父类静态初始化块
}
}
/**
* @author Lantzrung
* @date 2022年7月21日
* @Description
*/
public class Person {
public String name;
public String sex;
public int age;
static {
System.out.println("Person静态初始化块执行");
}
{
System.out.println("Person非静态初始化块执行");
}
public Person(String name, String sex, int age) {
super();
this.name = name;
this.sex = sex;
this.age = age;
System.out.println("Person全参构造器初始化块执行 ");
}
public Person() {
super();
System.out.println("Person无参构造器初始化块执行 ");
}
}
/**
* @author Lantzrung
* @date 2022年7月21日
* @Description
*/
public class Student extends Person {
static {
System.out.println("Student静态初始化块执行");
}
{
System.out.println("Student非静态初始化块执行");
}
public Student() {
super();
System.out.println("Student无参构造器初始化块执行 ");
}
public Student(String name, String sex, int age) {
super(name, sex, age);
System.out.println("Student全参构造器初始化块执行 ");
}
}