首页 > 代码库 > Java编程思想(Chapter2、4、6)

Java编程思想(Chapter2、4、6)

一切皆对象

用引用操纵对象

Java中操纵的标识符实际上是对象的“引用”。例如想要操纵一个字符串,则可以创建一个String引用。
String s;
此处s只是一个引用。

存储位置

基本类型/对象的引用:堆栈
对象: 堆

作用域

作用域由{}确定,决定了在其中定义的变量名的可见性以及生命周期。
1 {2     int x =12;3     {4         int x = 96; //illegal5     }6 }

非法,不能隐藏。

{    String s = new String("str");}
引用s在作用域终点消失,而s指向的String对象仍然占据着内存空间,直到gc销毁。

关于值传递还是引用传递的问题

Java中只存在值传递
1.基本类型的传递
  没有任何疑问,传值
2.对象的传递
  参数传递时,只存在传递基本类型和对象引用的问题,并不会直接传对象本身

一个方法不能修改一个基本数据类型的参数

一个方法可以改变一个对象参数的状态

一个方法不能让对象参数引用一个新的对象

参考知乎话题:java到底是值传递还是引用传递?传送门
对于参数是String类型,不修改原的原因在于 String 对象是final类型。

初始化与清理

初始化顺序

以一实例说明
public class Tag {    public Tag(int marker) {        System.out.println("tag"+marker);    }}
public class Card {    Tag tag = new Tag(1);    public Card() {        System.out.println("card()");        tag3 = new Tag(33);    }    Tag tag2 = new Tag(2);    void f(){        System.out.println("f()");    }    Tag tag3 = new Tag(3);}
public class Init01 {    public static void main(String[] args) {        Card card = new Card();        card.f();    }}

Result

技术分享
tag1tag2tag3card()tag33f()
View Code
可以看出先进行变量的初始化,再进行构造器调用。

在此基础上,如果还有静态数据时,顺序如何?

public class Bowl {    public Bowl(int marker) {        System.out.println("bowl "+marker);    }    protected void f(int marker){        System.out.println("f "+marker);    }}
public class Table {    static Bowl b1 = new Bowl(1);    public Table(){        System.out.println("table()");        b2.f(1);    }    void f2(int marker){        System.out.println("f2 "+marker);    }    static Bowl b2 =new Bowl(2);}
public class Cupboard {    Bowl b3 =new Bowl(3);    static Bowl b4 = new Bowl(4);    Cupboard(){        System.out.println("cup()");        b4.f(2);    }    void f3(int marker){        System.out.println("f3 "+marker);    }    static Bowl b5 = new Bowl(5);}
public class Test {    public static void main(String[] args) {        System.out.println("create cup in main");        new Cupboard();        System.out.println("create cup in main");        new Cupboard();        t2.f2(1);        t3.f3(1);    }    static Table t2 = new Table();    static Cupboard t3 = new Cupboard();}

Result

技术分享
bowl 1bowl 2table()f 1bowl 4bowl 5bowl 3cup()f 2create cup in mainbowl 3cup()f 2create cup in mainbowl 3cup()f 2f2 1f3 1
View Code
可以看出,先进行static静态数据的初始化(只执行一次),再普通变量的初始化,最后再调用构造器。

数组的初始化

每次访问数组时,都将进行数组的边界检测。

复用类

带参数的构造器

如果类没有缺省的参数,或者想调用一个带参数的基类构造器,则必须用super显示地编写调用基类构造器的语句。
public class C3 extends C2{    public C3(int i) {        super(i);//        System.out.println("c3");    }    public static void main(String[] args) {        new C3(1);    }}class C1{    public C1(int i) {        System.out.println("c1");    }}class C2 extends C1{    public C2(int i) {        super(i);//        System.out.println("c2");    }}
此处,两个super(i)都是必须,不然会报错。

初始化及类的加载

public class Insect {    protected int i = 9;    protected int j;    protected int x3 = print("static Insect.x3 init");    public Insect() {        System.out.println("i="+i+" ,j="+j);        j =39;    }    private static int x1 = print("static Insect.x1 init");    static int print(String s){        System.out.println(s);        return 47;    }}
public class Beetle extends Insect{    private int k = print("Beetle.k init");    public Beetle() {        System.out.println("k="+k);        System.out.println("j="+j);    }    private static int x2 = print("static Beetle.x2 init");    public static void main(String[] args) {        System.out.println("Beetle construct");        Beetle beetle = new Beetle();    }}

Result

技术分享
static Insect.x1 initstatic Beetle.x2 initBeetle constructstatic Insect.x3 initi=9 ,j=0Beetle.k initk=47j=39
View Code

可以看出,先进行类的加载,先基类再子类。static变量/块执行于类的初始化时期。new之后按照 先初始化再构造器的顺序执行。

Java编程思想(Chapter2、4、6)