JAVA编译器:
1. protable:一次编译,多次运行,平台独立
“.java“在运行程序的时候不需要,在编译阶段由编译器编译成".class"文件,再由不同版本的java虚拟机解释成不同平台上的native code
平台独立的原因:存在一种中间代码(.class,字节码)
2. 为了避免for这类语句的多次重复解释(耗时),java编译器中有个just-in-time compiler,使这一段编译后直接放到java虚拟机的内存中,而不是硬盘上的.class文件中。当然,每次重新编译程序的时候还是要重新编译。
3. 编译生成的.class文件的个数取决于class的个数,而不是文件的个数。
数据类型与包装类
如Integer是个类(包装类),int是个关键字。
具有自动装箱和拆箱的功能。
public static void f(int i){...;} //f的参数类型为int
int i = 0;
Integer ii = i; //自动装箱
f(ii); //ii为包装类的对象,自动拆箱
除char类型对应包装类为”Character“,int类型对应包装类为”Integer“,其他类型对应的包装类名称都是将它们的首字母大写。
在Java中,只有String类和包装类是immutable的类,即不可变的类(创建完后不能更改)。若要更改,则是产生一个新的对象再赋给原来的引用。
枚举类型
一个枚举类不能new出新的对象,相当于它的构造函数也是private的。
enum Direction{East, West, North, South}; //Direction为一个枚举类
//若
public void turnDirection(Direction d){...}
//则方法turnDirection只能传入以上4种值之一,否则编译器会报错
栈(stack)、堆(heap)、Class类对象的存放等
栈:
栈(stack)的数量 = 线程的数量
堆(heap):只有一个
变量variable:可以在栈中或者在堆中(以及Class类的对象中,static)
引用reference:可以在栈中或者在堆中(以及Class类的对象中,static)
对象:堆中(以及Class类的对象中,static)
f(){
Student s1 = new Student(); //把对象的地址赋给了s1
}
s1是一个引用,在f中(f在栈中)开辟了一块地方存s1(引用),对象实体new Student() 在heap中。
Class类对象的存放:
Class类:java.lang.Class类
Class类的构造函数是私有的,因此不能显式地创建一个Class类的对象(私有构造函数later->)
private Class(ClassLoader loader) {
classLoader = loader;
}
Java中,加载一个类定义的.class文件也是作为一个对象存放在内存中,这个对象由Class Loader(Class 类)创建。
ClassLoader在加载一个.class文件中的类定义时,才能自动创建一个这样的对象。这个对象不在堆中,也不在栈中。Java有一个专门的地方用来存放Class类对象。
垃圾回收
Java虚拟机判断是否为垃圾:
1. 引用计数:当stack中的引用被销毁,没有引用指向heap中的对象时,该对象被回收。
存在的问题:当heap中的多个对象荷香引用(指向)时,引用不为0,但因都没有来自stack的引用,本应都为垃圾,但没有被回收。(如下图右)
2. 类似于重力:
若该断没断,则对象不能掉入“垃圾场”,不能被回收。
Java中对象都在堆中,就算有GC(自动清理),也可能发生memory leak。
static
1. static类变量
static类变量(静态初始化):存放在Class类的对象中。在加载A类定义、创建Class类的对象时被初始化。只初始化一次(前提:方法区不做垃圾回收)
非static成员变量(构造初始化):存放在堆中的对象中。实际上是在每个重载的构造函数中初始化。每次重新调用构造函数都要创建一个新的。
class A{
int a; //非static成员变量
static int i; //static类变量
A(){} //相当于 A(){int a; ...}
A(int p){} //相当于 A(int p){int a; ...}
}
static与非static的区别在于:存放的位置不同
2. static类方法
对于方法而言,不管是否为static,它的可执行代码都在Class类的对象里面。它们的区别在于是否有“this”。
在内存中有一个方法区(Method Area),用来放方法的可执行代码(区别于heap)
static与非static的区别在于:有没有"this"
例:现有非static方法f(),static方法g()
public void f(){
g(); //可以调用,g不需要this而f有,不影响使用
}
public static void g(){
//f(); 不能调用,因为f需要this而g没有
}
3. static对象
static Hello h = new Hello();
//若不再想使用它时,应显式地
h = null;
若定义了一个static的对象,则当不再想使用它时,应显式地将它赋为null。
private构造函数
单例(singleton pattern):如果希望一个类只有一个对象,则把构造函数声明为private,然后直接创建一个static对象给用户使用。(如:一个windows系统只希望有一个回收站对象)
多例:同理单例,直接创建多个static对象给用户使用(如:方向类只有东南西北四个对象)
public class Hello{
public static void main(String[] args){
Person p1 = Person.getPerson(); //调用getPerson方法获取Person类对象
}
}
class Person{
private static Person p = new Person(); //私有静态对象
private Person(){} //私有构造函数
public Person getPerson(){ //公有函数获取静态对象
return p;
}
}
重载(overload)与重写(override)
重载(overload):由编译器决定调用哪个版本的重载函数,叫做早绑定(earlybind)
重写(override):在运行时(run-time)决定,叫做晚绑定(latebind)
如何判断两个对象的值是否相等
“Object”类提供了equals()方法,但这个方法本身与“==”没有区别,需要自己去重写
//A类中,由成员变量i
public boolean equals(Object obj){
return i == obj.i;
}