目录
一、static成员(补)
1.1. static修饰成员方法
1.2. static成员变量初始化
二、代码块
2.1. 静态代码块和实例代码块
三、对象的打印
一、static成员(补)
1.1. static修饰成员方法
public class Linear {
public static int count = 100;
public int func(){
Linear lin1 = new Linear();
Linear lin2 = new Linear();
Linear lin3 = new Linear();
lin1.count++;
lin2.count++;
lin3.count++;
Linear.count++;
return count;
}
}
public class Main {
public static void main(String[] args) {
Linear num = new Linear();
System.out.println(num.func());
}
}
老铁们猜一下打印的count是多少?这段代码具有迷惑性,老铁们可能猜会是101,而实际结果确实104。count因为被static修饰,就不属于对象了,所以count都是以同一个变量进行运算。class前的public是包访问权限,这个对象只能在同一个包中进行实例化访问。
而下面,博主将带大家进行更加直观的感受(接下来的代码可能会震碎你的三观):按常理推断我们给num赋值了一个null,按理说应该会抛出异常。可是我们一运行,照样会打印。这就是因为ret被static修饰,从而不属于任何对象。
public class demo {
public static String ret = "bite";
}
public class Main {
public static void main(String[] args) {
demo num = null;
System.out.println(num.ret);
}
}
1.2. static成员变量初始化
第一种是就地初始化,在定义时直接给出初始值。
public class Student{
private String name;
private String gender;
private int age;
private double score;
private static String classRoom = "107";
}
另一种是静态代码块初始化,接下来会讲到。
二、代码块
2.1. 静态代码块和实例代码块
以下是静态代码块与实例代码块的语法规则:
//静态代码块
static{
System.out.println("静态代码块被执行了");
}
//实例代码块
{
System.out.println("实例代码块被执行了");
}
package demo;
class Student{
private String name;
private int age;
private static String ClassRoom;
//实例代码块
{
System.out.println("实例代码块被执行了");
}
//静态代码块
static{
System.out.println("静态代码块被执行了");
}
public Student(String name, int age) {
this.name = name;
this.age = age;
System.out.println("构造Student(String name, int age)方法被执行了。。。");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class StarWars {
public static void main(String[] args) {
Student stu = new Student("Sandman",16);
}
}
以下为执行的结果:
从这里可以看到,执行的顺序是先执行静态代码块,再执行实例代码块,最后是构造方法。如果我们在new一个stu2的对象,再次执行,结果如下:静态代码块只被执行了一次。
如果我们在静态代码块里面,如果我们调用一个成员变量,则会产生报错。
三、对象的打印
Student stu1 = new Student("Sandman",16);
Student stu2 = new Student("Truck",18);
System.out.println(stu1);
System.out.println(stu2);
打印的结果我们可以理解为地址,@的左边demo包底下的Student类,右边是地址。当我们stu1和stu2这两个引用变量接受参数时,它是怎么调用的呢?我们看下println的源码。
public void println(Object x) {
String s = String.valueOf(x);
if (getClass() == PrintStream.class) {
// need to apply String.valueOf again since first invocation
// might return null
writeln(String.valueOf(s));
} else {
synchronized (this) {
print(s);
newLine();
}
}
}
当我们调用构造方法时,object类里的x会接收参数,接着传给valueOf里面;
//valueOf的源码
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
如果obj不是一个null,则会执行后面的toString;
//toString的源码
public String toString() {
return getClass().getName() + "@" + Integer.toHexString(hashCode());
}
最终返回并打印出的结果。
如果我们把toString的源码拿到我们的程序里面,把返回值改成我们想要打印的:
public String toString() {
return "Your name";
}