五、类的加载顺序
先看下列代码,猜看输出结果
提示(加载父类-----》子类-----》创建父类对象----》子类对象,有static先执行)
public class Test extends Base{
// 扫描(受检异常)-----》加载父类-----》子类-----》创建父类对象----》子类对象
// 子类调用父类的方法
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
结果
解析:先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
public class Demo {
public Demo(String aa){
System.out.println("===="+aa);
}
static {
System.out.println("11");
}
public static Demo demo = new Demo("+++");
static {
System.out.println("22");
}
}
class Test{
public static void main(String[] args) {
Demo demo = new Demo("----");
}
}
输出结果
- 11
- ====+++
- 22
- ====----
下面是一个测试用例
/**
* @ClassName TRRest
* @Description TODO
* @Author heaboy@heaboy.com
* @Version 1.0.0
*/
public class InitializeDemo {
private static int k = 1;
private static InitializeDemo t1 = new InitializeDemo("t1");
private static InitializeDemo t2 = new InitializeDemo("t2");
private static int i = print("i");
private static int n = 99;
{
print("构造块");
j=100;
}
public InitializeDemo(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++i;
++n;
}
static {
print("静态块");
n=100;
}
private int j = print("j");
public static int print(String str) {
System.out.println((k++) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
}
六、值传递和引用传递 -----》java之后值传递
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
Java中只有值传递。
值传递:值传递是将值得地址值传递过去
引用传递:将句柄的地址传递过去
我们可以看一下代码:
public static void main(String[] args) {
String nameString = "张三";
name(nameString);
System.out.println("main--->"+nameString);
}
public static void name(String name) {
name = "李四";
System.out.println("name--->"+name);
}
这一次拷贝的是nameString 值"张三",name的值就是张三,所以当name的值不管怎么变化,nameString是不变的。
那我们来看一下这个
public class Person {
private String nameString;
private int age;
public Person(String nameString,int age) {
this.age = age;
this.nameString = nameString;
}
@Override
public String toString() {
return "Person [nameString=" + nameString + ", age=" + age + "]";
}
public static void name(Person person) {
person.age =20;
person.nameString="李四";
person = null;
}
public static void main(String[] args) {
Person person = new Person("张三",18);
System.out.println(person.toString()); //参数改变前
name(person);
System.out.println(person.toString()); // 参数改变后
}
}
结果:
- Person [nameString=张三, age=18]
- Person [nameString=李四, age=20]
下面是一些代码案例
public class Student {
private String name;
private int age;
public Student(String name,int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
public static void change(Student s1, Student s2){
Student temp = new Student("王五",20);
temp = s1;
s1 = s2;
s2 = temp;
}
public static void main(String[] args) {
Student zhangsan = new Student("张三", 18);
Student lisi = new Student("李四", 20);
Student.change(zhangsan, lisi);
System.out.println(zhangsan.toString());
System.out.println(lisi.toString());
}
}
输出结果
Student [name=张三, age=18]
Student [name=李四, age=20]
class Two{
Byte x;
}
public class Student {
public static void main(String[] args) {
Student student = new Student();
student.start();
}
void start() {
Two two = new Two();
System.out.print(two.x +" ");
Two two2 = fix(two);
System.out.println(two.x + " "+two2.x);
}
Two fix(Two tt) {
tt.x = 42;
return tt;
}
}
A: null null 42
B:null 42 42
C:0 0 42
D:0 42 42
E:Anexception is thrown at runtime