一、方法重载 overload
1、 构造方法的重载
1)如果类中没有默认的构造方法,编译器会自动添加;如果存在了构造方法,编译器将不再添加默认构造方法,因为它会认为你已经很明白如何构造此类了。
2)构造方法的名字都是类名,没有返回值。
3)在构造方法中可以通过this关键字来调用其他的构造方法,如this("hello"); 必须将这一句话写在最前面,而且只能在构造函数中这么使用。因此一个构造函数
当中只能调用一次this(xxx); 因为写第二句的时候已经不满足“
this(xxx) 只能出现在构造方法的最前面”这一条件 了
2、 区分方法重载
1)
每个重载的方法都必须有一个独一无二的参数类型列表,这是唯一的区分方法。返回值类型的不同无法区分两个重载的方法。
如 void f(int i) 和 int f(int i), 当系统调用时,不返回任何值时,就会产生歧义,无法知晓调用的方法,因此只能通过参数列表区分两个重载的方法
2) 可变的参数列表
void f(Object[] args); //参数的数量和类型都是可变的 , 也可以写成 void f(Object ... args);
通过代码来更深体会一下:
public class VariousParams{
static void func(float f, Character ... chars){
System.out.println("first float"+f);
for(Character ch : chars){
System.out.print(ch+"\t");
}
}
/*static void func(Character ... chars){ //如果直接使用这个,因为自动包装机制,会将第一个字符转换成float,也可以是char,有歧义
System.out.println("second ");
for(Character ch : chars){
System.out.print(ch+"\t");
}
}*/
static void func(int i,Character ... chars){//改进后的方法。添加一个非可变参数
System.out.println("second int"+i);
for(Character ch : chars){
System.out.print(ch+"\t");
}
}
public static void main(String args[]){
func('a','b','c');//如果不引入非可变参数,这会引起歧义,因为Java的自动包装机制
System.out.println();//优先选择可以直接匹配的,再考虑强制转换
func(1.0f,'a','b','c');
}
}
二、垃圾回收 Garbage Collection
1、基本原则
对象可能不被垃圾回收;垃圾回收不等于析构;垃圾回收只与内存有关
2、finalize
程序员可以自己干预某些对象的垃圾回收,一般是调用了JNI的方法,使用其他语言分配的内存,垃圾回收机制无法操控这些,如果不释放,易内存泄露。
使用方式举例:
public class SystemTest{
public static void main(String args[]){
Book b=new Book("1");
b.checkout(); //正常终止
new Book("2"); //没有正常结束的对象
new Book("3");
// new Book("4");
System.gc(); //调用系统的垃圾回收器,强制进行终结动作,会调用系统中没有被清理的对象的finalize方法,输出的结果会是最近一个对象book3
}
}
class Book{
private boolean checkout;
private String name;
public Book(String s){
checkout=false;
name=s;
}
public void checkout(){
checkout=true;
System.out.println("check out the book "+name);
}
protected void finalize(){ //override finalize方法
if(!checkout){
System.err.println("book "+name+" hadn't been checked out--Garbage Collection");
this.checkout();
}else{
System.out.println("Normal checked");
}
}
}
3、 垃圾回收器
JVM garbage collector 的特点是: 自适应auto-fit、分代的generation count、停止-复制 stop-copy、标记-清扫mark-sweep
stop-copy: 是将正在运行的程序暂停下来,把原来在堆中的对象复制到另一块堆内存中,更新引用所指向的对象。为的是使堆中对象紧凑排列,减少碎片,避免页错误,
方便以后新对象的堆内存分配
mark-sweep:遍历所有对象的引用,找到存活着的对象并标记好,全部标记完成后,开始释放没有被标记的对象
自适应:stop-copy非常耗费空间和时间,但是当内存中出现很多碎片,堆内存分配不容易时,选择这个是合理的;当对象很稳定,垃圾对象较少时使用mark-sweepj将
会是一个不错的选择,JVM会检测这些对象的状态,然后选择合理的回收方式,这就是自适应。
分代: 每个块都有相应的代数以记录是否还存活,没引用一次该对象就增加一次它的代数,经常被引用的对象就不会被stop-copy拷贝整理,减少页错误。
三、初始化顺序
1) 成员变量的初始化会在构造函数之前,如
class A {
int n=1; //先执行这个
A(int n1, char c1){//最后执行
System.out.println("n="+n+" c="+c);
this.n=n1;
this.c=c1;
System.out.println("n="+n+" c="+c);
}
char c='b'; //再执行这个
}
2) 静态数据的初始化只有在必要时才进行,不用他它就不初始化,创建了该对象的实例或者直接用类调用了他才会初始化仅此一次,跟它在代码中的位置无关
静态数据的位置与它初始化的顺序毫无关系,它先于成员变量初始化,然后又构造方法初始化
以下代码可以更好的理解这些:
public class StaticIntialize{
static B b=new B(1);//静态成员
public static void main(String args[]){
System.out.println("main ()");
}
static B b2=new B(2);//静态成员
}
class A {
A(int id){
System.out.println("create A"+id);
}
}
class B{
static A sa1=new A(1); //静态成员
private A aB=new A(2); //成员变量
B(int id){
System.out.println("new a B"+id);
}
static A sa2=new A(3);//静态成员
}
//结果:
create A1
create A3
create A2
new a B1
create A2
new a B2
main ()
四、 枚举类型enum
关键字enum修饰的类,跟其他类其实差不多,只是有些新的特性,它里面的每个元素都有一个整数值,即出现的顺序,调用ordinal()可呈现
可以在switch( EnumObject) case A: ....
写个例子就很熟悉了:
public enum enumLetter{
A_PLUS("A+",5.0), A_MINUS("A-",4.6),
B_PLUS("B+",4.1), B_MINUS("B-",3.6),
C_PLUS("C+",3.1), C_MINUS("C-",2.6),
D_PLUS("D+",2.1), D_MINUS("D-",1.6);
private final String grade;
private final double point;
private enumLetter(String grade,double point){
this.grade=grade;
this.point=point;
}
public String getGrade(){
return grade;
}
public double getPoint(){
return point;
}
public static void main(String[] args){
enumLetter myGrade=enumLetter.A_PLUS;
enumLetter hisGrade=enumLetter.A_MINUS;
enumLetter herGrade=enumLetter.A_PLUS;
System.out.println("my grade: "+myGrade+" order:"+myGrade.ordinal());
System.out.println("his grade: "+hisGrade+" order:"+hisGrade.ordinal());
System.out.println("her grade: "+herGrade+" order:"+herGrade.ordinal());
System.out.println("my grade ==her grade? "+(herGrade==myGrade));
System.out.println("my grade equals her grade? "+(herGrade.equals(myGrade)));
System.out.println("enumLetter.valueOf(\"C_PLUS\"): "+enumLetter.valueOf("C_PLUS"));
System.out.println("enumLetter.valueOf(\"C_PLUS\").getPoint(): "+enumLetter.valueOf("C_PLUS").getPoint());
}
}
//结果
my grade: A_PLUS order:0
his grade: A_MINUS order:1
her grade: A_PLUS order:0
my grade ==her grade? true
my grade equals her grade? true
enumLetter.valueOf("C_PLUS"): C_PLUS
enumLetter.valueOf("C_PLUS").getPoint(): 3.1 //可以直接通过值获得那个枚举对象
五、访问权限控制
1、 权限
public , protected, private , 同包访问 共四种
2、 细则
每个Java源文件,只能有一个public 修饰的类,该类必须与文件同名,通常用它来包含主函数,其他的默认为同包访问权限
除了内部类,其他
任何的类不能是private 和protected 修饰的,这样会阻止外界创建该类,也就没什么存在的价值了。
若不希望其他类创建该类的对象,可以将所有的构造方法都用private 来修饰,需要注意的是:
该
类的static 成员可以访问该private 修饰的构造方法,以此来创建实例,单例模式使用的就是这个特性,程序如下:
public class Singleton {
public static void main(String[] args){
A.newInstance().showName();
}
}
class A {
private String name;
private A(String s){
this.name=s;
}
private static A single=new A("single instance");//唯一被创建的A的对象
public static A newInstance(){//只有这一个对象可以返回
return single;
}
public void showName(){//外界可以调用这个方法来获得A的属性
System.out.println("my name is "+name);
}
}