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

一切皆对象

用引用操纵对象

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

存储位置

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

作用域

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

非法,不能隐藏。

{
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

tag1
tag2
tag3
card()
tag33
f()
可以看出先进行变量的初始化,再进行构造器调用。

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

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 1
bowl 2
table()
f 1
bowl 4
bowl 5
bowl 3
cup()
f 2
create cup in main
bowl 3
cup()
f 2
create cup in main
bowl 3
cup()
f 2
f2 1
f3 1
可以看出,先进行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 init
static Beetle.x2 init
Beetle construct
static Insect.x3 init
i=9 ,j=0
Beetle.k init
k=47
j=39

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

上一篇:Sublime Text 3打开gbk编码的文件中文乱码的问题


下一篇:Maven入门-依赖管理(Jar包管理)(二)