java基础知识点集合

放在if之后括号里的只能是一个逻辑表达式,即这个表达式的返回值只能是true或false

 

建议不要省略if、else、else if后执行体的或括号,即使执行体只有一行代码,也保留或括号会更好的可读性,而且保留花括号会减少发生错误的可能。

 

switch语句后面的控制表达式的数据类型只能是byte、short、char、int四个整数类型和枚举类型,不能是boolean类型

java7允许switch语句中的控制表达式为java.lang.String类型,不能是StringBuffer和StringBuilder类型

 

[init_statement]

while(test_expression){

statement;

[iteration_statement];

}

 

for循环圆括号中只有两个分号是必须的,初始化语句、循环条件、迭代语句部分都是可以省略的,如果省略了循环条件,则这个循环条件默认为true,将会产生一个死循环

//省略了for循环三个部分,循环条件将一直为true

 

for(;;){
    System.out.println("===========");
}

//下面这种方式有点仿while循环

int count=0;

for(;count<10;){

    System.out.println(count);

    count++;

}

 

 

java提供了continue和break来控制循环结构,除此之外,return也可以结束整个方法,当然也就结束了一次循环

break默认就是结束其所在的循环

continue只是终止本次循环

 

为什么有堆内存和栈内存之分?

当执行一个方法的时候,每个方法都会建立自己的内存栈,在这个方法内定义的变量将会逐个放入这块栈内存里,随着方法的执行结束,这个方法的内存栈也将自然销毁。

因此,所有在方法中定义的局部变量都是放在栈内存中的,当我们在程序中创建一个对象时,这个对象将被保存到运行时数据区中,以便反复利用(因为对象的创建成本通常较大),这个运行时数据区就是堆内存。堆内存中的对象不会随着方法的结束而销毁,即使方法结束后,这个对象还可能被另一个引用变量引用(在方法的参数传递时很常见),则这个对象依然不会被销毁。只有当一个对象没有任何引用变量引用它时,系统的垃圾回收器才会在合适的时候收回他。

 

如果堆内存中的数组不再有任何引用变量指向自己,则这个数组将成为垃圾,该数组所占的内存将会被系统的垃圾回收机制收回。因此,为了让垃圾回收机制收回一个数组所占的内存空间,可以将该数组变量赋为Null,也就切断了数组引用变量和实际数组之间的引用关系,实际数组也就成为了垃圾。

 

如果程序员没有为一个类编写构造器,则系统会为该类提供一个默认的构造器。一旦程序员为一个类提供了构造器,系统将不再为该类提供构造器。

 

static修饰的成员表明它属于这个类本身,而不属于该类的单个实例,因为通常把static修饰的field和方法也称为类field、类方法。

 

构造方法:

1、构造方法名必须和类名完全相同

2、不能定义返回值类型,也不能使用void定义构造方法的返回值。

 

static修饰的方法和field,既可以通过类来调用,也可以通过实例来调用;没有使用static修饰的普通方法和field,只能通过实例来调用 

 

当一个对象被创建成功以后,这个对象将被保存在堆内存中,java程序不允许直接访问堆内存中的对象,只能通过该对象的引用操作对象。也就是说,不管是数组还是对象,都只能通过引用来访问他们。

 

如果堆内存里的对象没有任何变量指向该对象,那么程序将无法再访问该对象,这个对象也就变成了垃圾,java垃圾回收机制将回收该对象,释放该对象所占的内存区。因此,如果希望通过垃圾回收机制来回收某个对象,只需要切断该对象的所有引用变量和它之间的关系即可,也就是把这些引用变量的值赋值为Null。

 

this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类;只有当这个方法被调用的时候,它所代表的对象才被确定下来——谁在调用这个方法,this就代表谁

 

对于static修饰的方法而言,则可以使用类来直接调用该方法,如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。所以static修饰的方法中是不能使用this引用的,由于static修饰的方法不能使用this引用,所以static修饰的方法不能访问不使用static修饰的普通成员。

因此java语法规定:静态成员不能直接访问非静态成员

 

如果确实要在静态方法中访问另一个普通方法,则只能重新创建一个对象。

 

在构造方法中使用this引用时,this总是引用该构造方法正在初始化的对象

 

在java语言里,方法不能独立存在,必须属于类或者对象,如果这个方法使用了static修饰,则这个方法属于这个类,否则这个方法属于这个类的实例

 

同一个类的一个方法调用另外一个方法时,如果被调用方法时普通方法,则默认使用this作为调用者,如果被调用方法是静态方法,则默认使用类作为调用者

 

使用static修饰的方法既可以使用类作为调用者来调用也可以使用对象作为调用者来调用

 

java里方法参数传递的方式只有一种——值传递。即将实际参数值的副本(复制品)传入方法内,而参数本身不会受到任何影响。

 

JDK1.5之后,允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参,如果在定义方法时,在最后一个形参的类型后增加三点(...),则表明该形参可以接受多个参数值,多个参数值被当做数组传入

注意:长度可变形参只能处于形参列表最后面,一个方法最多只能包含一个长度可变参数

 

public class Varargs{
	public static void test(int a,String... books){
		for(String book : books){
			System.out.println(book);
		}
	}
}

  

如果同一个类定义了test(String... books)和test(String book)方法,如果只传入一个参数,系统会执行重载test(String book)方法,如果需要调用test(String... books)方法,又只想传入一个字符串数组,则可以采用传入字符串数组的形式

test(new String[]{"aaa"});

一般不推荐重载形参长度可变的方法。没有意义,降低了可读性

 

成员变量指的是在类范围里定义的变量,局部变量指的是在方法里定义的变量

 

成员变量分为两种:

static修饰的是类Field——从类的准备阶段起开始存在,直到系统完全销毁这个类,类Field的作用域与这个类的生存范围相同

没有被static修饰的是实例Field——从该类的实例被创建开始存在,知道系统完全销毁这个实例,实例Field的作用域与对应的实例生存范围相同

 

成员变量无需显示初始化,只要为一个类定义了类Field或实例Field,系统就会在这个类准备阶段或者创建该类的实例时进行默认初始化,成员变量默认初始化时的赋值规则与数组动态初始化时数组元素的赋值规则完全相同

 

局部变量:1、形参 2、方法局部变量 3、代码块局部变量

与成员变量不同的是,局部变量除了形参之外都必须显示初始化。

 

java允许局部变量和成员变量同名,局部变量会覆盖成员变量,如果需要在这个方法里面引用被覆盖的成员变量,则可以使用this或者类名作为调用者来限定访问的成员变量

 

局部变量不属于任何类或者实例,因此它总是保存在其所在方法的栈内存中

 

java允许将一组功能相关的类放在同一个package下,从而组成逻辑上的类库单元

 

构造器最大的用处就是在创建对象时执行初始化,系统为这个对象的Field进行默认初始化,把值设为0,false,null;如果想改变值则可以通过构造器来实现

 

构造器不能直接被调用,构造器必须使用new关键字来调用。为了在构造器B中调用构造器A中的代码初始化,又不会重新创建一个JAVA对象,可以使用this关键字来调用相应的构造器

public class Apple{
	public String name;
	public String color;
	public double weight;
	 
	public Apple(){
	}
	 
	public Apple(String name,String color){
		this.name = name;
		this.color = color;
	}
	 
	public Apple(String name,String color,double weight){
		this(name,color);
		this.weight = weight;
	}
 
} 

 

备注:使用this调用另一个重载的构造器只能用在构造器中,而且必须作为构造器执行体的第一条语句

 

当子类覆盖了父类方法后,子类的对象将无法访问父类中被覆盖的方法,但可以在子类方法中调用父类中被覆盖的方法。如果需要在子类方法中调用父类被覆盖的方法,则可以使用super(被覆盖的实例方法)或者父类类名(被覆盖的是类方法)作为调用者来调用父类中被覆盖的方法

 

如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法,也就是无法重写该方法。如果子类中定义了一个与父类private方法具有相同方法名、形参列表、返回值类型的方法,这依然不是重写,只是在子类中重新定义了一个新方法。

 

super用于限定该对象(重点是对象)调用它从父类继承得到的Field或方法。正如this不能出现在static修饰的方法中一样,super也不能出现在static修饰的方法中

 

如果在某个方法中访问名为a的Field,但是没有显示指定调用者,则系统查找a的顺序为:

1、查找该方法中是否有a的局部变量

2、查找当前类中是否包含名为a的Field

3、查找a的直接父类中是否包含名为a的Field,依此上溯a的所有父类,知道Object类,如果还没有找到则系统出现编译错误

 

子类中定义与父类中同名的实例变量并不会完全覆盖父类中定义的实例变量,它只是简单地隐藏了父类中的实例变量

 

相同类型的变量,调用同一个方法呈现出多种不同的行为特征,这就是多态。(子类扮演父类的角色,实际是子类的行为)

 

如果父类中的方法需要被外部调用,必须以public修饰,但是又不希望子类重写该方法,可以使用final修饰,如果希望父类的方法被子类重写,但是不希望被其他类重写则可以使用protected来修饰

 

尽量不要在父类构造器中调用将要被子类重写的方法,因为一旦被重写他访问的不是父类的方法,而是重写的方法,可能出现异常情况

 

何时从父类派生新的子类?

1、子类需要额外增加属性,不仅仅是属性值的改变

2、子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)

 

继承要表达的是一种“是(is a)”的关系,而组合表达的是“有(has a)”的关系

 

一个类里可以有多个初始化块,相同类型的初始化块之间有顺序:前面定义的初始化块先执行,后面定义的初始化块后执行

初始化块的修饰符只能是static,要么就不要

[static]{

//初始化块的可执行代码

}

 

初始化块虽然也是java类的一种成员,但是他没有名字,也就没有标识,因此无法通过类、对象来调用初始化块。初始化块只能在创建java对象时隐式执行,而且在执行构造器之前执行

 

初始化顺序:先执行初始化块或Field时指定的初始值(前面按照代码顺序执行),再执行构造器里指定的初始化值

 

public class Test2 { 
	int a = 6;
	{
		a=9;
	}
    public static void main(String[] args) throws ClassNotFoundException{ 
    System.out.println(new Test2().a);//打印9
	//如果初始化块放在前面打印的是6
    } 
}

 

 

静态初始化块是类相关的,系统将在类初始化阶段执行静态初始化块,而不是在创建对象时才执行。因此静态初始化块总是比普通初始化块先执行

 

一个方法体内调用它自身,被称为方法递归

 

java程序直接使用形如“hello”的字符串直接量时,JVM将会使用常量池来管理这些字符串;当使用new String("hello")时,JVM会先使用常量池来管理“hello”直接量,再调用String类的构造方法来创建一个新的String对象,新创建的String对象呗保存在堆内存中

 

JDK1.5以后支持所谓的自动装箱,即可以直接把一个基本类型值赋给一个包装类实例

Integer ina = 2;

备注:这个整数自动装箱的数字范围是-128到127,超过这个范围就不能实现自动装箱了,可以查看Integer源代码

 

==:基本类型判断数值相等,如果是引用类型比较,他们必须指向同一个对象(内存地址一致)

 

对于instanceof运算符而言,当签名对象是后面类的实例或者其子类的实例时都将返回true,所以实际上重写equals()方法判断两个对象是否是同一个类的实例使用instanceof是有问题的

 

当使用实例来访问类成员时,实际上依然是委托给该类来访问类成员,因此即使某个实例为Null,它也可以访问它所属类的类成员。

public class NullAccessStatic{
	private static void test(){
		System.out.println("test");
	}
 
	public static void main(String[]args){
		NullAccessStatic nas = null;
		nas.test();//结果打印test
	}
}

 

对static关键字而言,有一条非常重要的规则:类成员(方法、初始化块、内部类和枚举)不能访问实例成员(Field、方法、初始化块、内部类和枚举)。因为类成员的作用域比实例成员作用域更大,完全可能出现类成员已经初始化完成,但实例成员还不曾初始化的情况。

 

创建单例对象

1、把该类的构造器隐藏起来,使用private修饰

2、需要提供一个public方法作为创建该类的对象,而且必须是static的,因为调用该类之前还不存在对象,所以只能是类去调用这个方法

3、还必须缓存已经创建的对象,否则无法知道该类是否已经创建了对象,也就无法保证只创建一个对象

 

final修饰类、变量、方法,final修饰表示变量一旦获得了初始值就不可被改变(是可以被赋值的)

 

因为形参在调用该方法时,由系统根据传入的参数来完成初始化,因此使用final修饰的形参不能被赋值。

 

final修饰的成员变量必须由程序员显示地指定初始值,系统不会对final成员进行隐式初始化

 

如果final修饰的局部变量在定义时没有指定默认值,则可在后面代码中对该final变量赋初始值,但只能一次,不能重复。

 

final修饰基本类型变量时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。

使用final修饰的引用类型变量不能被重新赋值(引用变量所引用的地址不能被改变),但可以改变引用类型变量引用对象的内容

 

可执行“宏替换”的final变量

1、使用final修饰符

2、在定义该final变量时指定了初始值

3、该初始值可以在编译时就被确定下来

满足上面三个条件,这个final变量就不再是一个变量,而是相当于一个直接量。

编译器会把程序中所有用到该变量的地方直接替换成该变量值。

除了那种为final变量赋值时赋直接量的情况外,如果被赋的表达式只是基本的算术表达式或者字符串连接运算,没有访问普通变量,调用方法java编译器同样会将这种final变量当成“宏变量”处理

例如:下面定义了4个final“宏变量”

final int a = 5 + 2;

final double b = 1.2/3;

final String str = "疯狂" + "java";

final String book = "疯狂java讲义" + 99.0;

 

java会使用常量池来管理曾经用过的字符串直接量,例如执行String a = "java";系统的字符串池中会缓存一个字符串"java";如果程序再次执行String b="java";系统将会让b直接指向字符串池中的"java"字符串,因此a==b返回true

 

对于final实例变量而言,只有在定义该变量时指定初始化值才会有“宏变量”的效果

 

final修饰的方法不可被重写,如果处于某些原因,不希望子类重写父类的某个方法,则可以使用final修饰该方法。

 

使用final修饰一个private访问权限的方法,依然可以在其子类中定义与该方法具有相同方法名、相同形参列表、相同返回值类型的方法。(因为private修饰的方法,子类无法访问,所以子类无法重写该方法)

 

final修饰的类不可能有子类

 

不可变类(String,Double等)的意思是创建该类实例后,该实例的Field是不可改变的。

创建自定义不可变类,可遵守如下规则:

1、使用private和final修饰符来修饰该类的Field

2、提供带参数的构造器,根据传入参数来初始化类里的Field

3、仅为该类的Field提供getter方法不提供setter方法

4、如果有必要重写equals和hashCode方法。

 

 

有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法。

抽象方法和抽象类的规则如下:

1、抽象类和抽象方法必须使用abstract修饰符来修饰,抽象方法不能有方法体(具体实现)

2、抽象类不能被实例化,即无法使用new关键字。即使抽象类里没有抽象方法。

3、抽象类的构造方法不能用于创建实例,主要是用于被其子类调用

4、直接定义抽象方法;继承了一个抽象父类,但没有完全实现父类包含的抽象方法;以及实现一个接口,但是没有完全实现接口包含的抽象方法;这三种情况只能被定义成抽象类。

 

final修饰的类不能被继承,方法不能被重写,因此final和abstract永远不能同时使用。

 

abstract不能用于修饰Field,不能用于修饰局部变量,即没有抽象变量、没有抽象Field等说法;abstract也不能用于修饰构造器,没有抽象构造器,抽象类里定义的构造器只能是普通的构造器。

 

static修饰一个方法表示这个方法属于类本身;如果该方法被定义为抽象方法,则将导致通过该类来调用该方法出现错误(调用了一个没有方法体的方法肯定会引起错误的)。因此static和abstract不能同时修饰某个方法,即没有所谓的类抽象方法。

 

abstract修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体,因此abstract方法不能定义为private访问权限,即private和abstract不能同时使用。

 

接口体现的是规范和实现分离的设计哲学。让软件系统的各个组件之间面向接口耦合,是一种松耦合的设计

 

一个接口可以有多个直接父接口,但接口只能继承接口,不能继承类。

 

由于接口定义的是一种规范,因此接口里不能包含构造器和初始化块定义。接口里可以包含Field(只能是常量)、方法(只能是抽象实例方法)、内部类(包括内部接口、枚举)定义。访问控制符只能是public或者是省略public(包权限访问控制符即只能在相同的包结构下才可以访问该接口)

 

对于接口里定义的常量Field而言,他们是接口相关的,而且它们只能是常量,因此系统会自动为这些field增加static和final两个修饰符。也就是说,在接口中定义field时,不管是否使用public static final修饰,接口里field总将使用这三个修饰符来修饰。接口里没有构造器和初始化块,因此接口里定义的field只能定义时指定默认值。

 

对于接口里定义的方法而言,他们只能是抽象方法,因此系统会自动为其添加abstract修饰符,由于接口里的方法全部都是抽象方法,因此接口里不允许定义静态方法,即不可使用static修饰接口里定义的方法。不管定义接口里方法是否使用public abstract修饰符,接口里的方法总是使用public abstract来修饰

 

abstract interface interfaceA
{
    public static final int PROP_A = 5;
 
    public abstract void testA();
}
 
abstract interface interfaceB
{
    public static final int PROP_B = 6;
 
    public abstract void testB();
}
 
public abstract interface interfaceC extends interfaceA, interfaceB {
public static final int PROP_C = 7;
 
public abstract void testC();
}

 

备注:abstract修饰符可以要可以不要。

 

把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(嵌套类),包含内部类的类也被称为外部类(宿主类)

 

1、内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类

2、内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间是可以相互访问

3、匿名内部类适用于创建那些仅需要一次使用的类

 

在方法中也可定义内部类(方法里定义的内部类被称为局部内部类)。大部分内部类都被作为成员内部类定义,而不是作为局部内部类。成员内部类是一种与Field、方法、构造器和初始化块相似的类成员;局部内部类和匿名内部类则不是类成员。

 

内部类:静态内部类和非静态内部类

 

成员内部类(静态内部类、非静态内部类)的class文件总是这样的形式:OuterClass$InnerClass.class;例如:Cow$CowLeg.class

 

非静态内部类的成员可以访问外部类的private成员,但是反过来就不成立了。非静态内部类的成员只在非静态内部类范围内是可知的,并不能被外部类直接使用。如果外部类需要访问非静态内部类的成员,则必须显示创建非静态内部类对象来调用访问其实力成员。

 

非静态内部类对象必须寄存在外部类对象里,而外部类对象则不必一定有非静态内部类对象寄存其中。因此外部类对象访问非静态内部类成员时,可能非静态普通内部类对象根本不存在,而非静态内部类对象访问外部类成员时,外部类对象是一定存在的。

 

根据静态成员不能访问非静态成员的规则,外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例等。总之,不允许在外部类的静态成员中直接使用非静态内部类。

 

非静态内部类里不能有静态方法、静态Field、静态初始化块。

 

静态内部类:

如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不是属于外部类的某个对象,因此使用static修饰的内部类被称为类内部类(静态内部类)

 

外部类的上一级程序单元是包,所以不可使用static修饰,而内部类的上衣程序单元是外部类,使用static修饰可以将内部类变成外部类相关,而不是外部类实例相关。

 

静态内部类可以包含静态成员,也可以包含非静态成员。根据静态成员不能访问非静态成员的规则,静态内部类不能访问外部的实例成员,只能访问外部类的类成员。即使静态内部类的实例方法也不能访问外部类的实例成员,只能访问外部类的静态成员。

 

当静态内部类对象存在时,并不存在一个被他寄存的外部类对象,静态内部类对象里只有外部类的类引用,没有持有外部类对象的引用。如果允许静态内部类的实例方法访问外部类的实例成员,但找不到被寄存的外部类对象,这将引起错误。

 

静态内部类是外部类的一个静态成员,因此外部类的静态方法、静态初始化块中可以使用静态内部类来定义变量、创建对象等。

 

java还允许在接口里定义内部类,接口里定义的内部类默认使用public static修饰,也就是说,接口内部类只能是静态内部类。

 

非静态内部类的构造器必须使用外部类对象来调用;例如:

Out.In in = new Out().new In("...");

 

非静态内部类的子类不一定是内部类,它可以是一个外部类。但非静态内部类的子类实例一样需要保留一个引用,该引用指向其父类所在的外部类对象。

 

使用静态类比使用非静态内部类要简单很多,只要把外部类当成静态内部类的包空间即可,因此当程序需要使用内部类时,应该优先考虑使用静态内部类。

 

问:既然内部类是外部类的成员,那么是否可以为外部类定义子类,在子类中再定义一个内部类来重写其父类中的内部类?

不可以!内部类的类名不再是简单地由内部类的类名组成,它实际上还把外部类的类名作为一个命名空间,作为内部类类名的限制。因此子类中的内部类和父类中的内部类不可能完全同名,即使二者所包含的内部类类名相同,但因为他们所处的外部类空间不同,所以它们不可能完全同名,也就不可能重写。

 

对于局部内部类成员而言,不管是局部变量还是局部内部类,他们的上一级程序单元是方法,而不是类,使用static修饰他们是没有任何意义的,因此局部成员都不可能使用static修饰,不仅如此,因为局部成员的作用域是所在方法,其他程序单元永远一不可能访问一个方法中的局部成员,所以所有的局部成员都不能使用访问控制符修饰。

 

局部内部类的class文件总是遵循如下命名格式:OuterClass$NInnerClass.class;局部内部类的class文件的文件名比成员内部类的class文件的文件名多了一个数字,因为同一个类里不可能有两个同名的成员内部类,而同一个类里则可能有两个以上同名的局部内部类(处于不同的方法中)

 

定义匿名内部类的格式如下:

new 父类构造器(实参列表)|实现接口(){

//匿名内部类的类体部分

}

 

匿名内部类有如下两条规则:

1、匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象

2、匿名内部类不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化,通过实例初始化块来完成构造器需要完成的事情。

 

如果匿名内部类需要访问外部类的局部变量,则必须使用final修饰符来修饰外部类的局部变量。

 

所谓回调,就是允许客户类通过内部类引用来调用其外部类的方法,这是一种非常灵活的功能。

 

java5新增了一个enum关键字(它与class、interface关键字地位相同),用以定义枚举类。枚举类是一种特殊的类,他一样可以有自己的Field、方法,可以实现一个或多个接口,也可以定义自己的构造器。

 

枚举类与普通类鹅区别:

1、枚举类可以实现一个或者多个接口,使用enum定义的枚举类默认继承了java.lang.Enum类,而不是继承Object类。其中java.lang.Enum类实现了java.lang.Serializable和java.lang.Comparable两个接口

2、使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派生子类

3、枚举类的构造器只能使用private访问控制符,不管是默认还是强制指定控制符,都只能是private

4、枚举类的所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远都不能产生实例。列出的实例系统会自动添加public static final修饰,无须程序员显示添加。

 

 

jar(java archive file)即java档案文件,jar文件与zip文件的区别就是在jar文件中默认包含了一个名为META-INF/MANIFEST.MF的清单文件,这个清单文件是在生产JAR文件时由系统自动创建的。

 

Object类是所有类、数组、枚举的父类

 

Object类的toString()方法返回“运行时类名@十六进制hashCode值”格式的字符串。

 

Java提供了一个protected修饰的clone()方法,该方法用于帮助其他对象来实现“自我克隆”,所谓“自我克隆”就是得到一个当前对象的副本,而且两者之间完全隔离,该方法只能被子类重写或调用。

 

自定义类实现“克隆”的步骤:

1、自定义类实现Cloneable接口;(这是个标记性接口,实现该接口对象可以实现“自我克隆”,接口里没有定义任何方法,否则不能执行clone方法)

2、自定义类实现自己的clone()方法

3、实现clone()方法时通过super.clone();调用Object实现的clone()方法来得到该对象的副本,并返回该副本。

 

备注:标记性接口是没有任何方法和属性的接口。它仅仅表明他的类属于一个特定的类型,供其他代码来测试允许做一些事情。使用标记性接口的唯一目的是使得可以用instanceof进行类型查询,例如:

if(obj instanceof Cloneable){......}

一些容器例如EJB容器,servlet容器或运行环境依赖标记接口识别类是否需要进行某种处理,例如serialiable接口标记类需要进行序列化操作。

 

class Address{
	String detail;
	public Address(String detail){
		this.detail = detail;
	}
}

 

public class User implements Cloneable{
	 
	int age;
	Address address;
	public User(int age){
		this.age = age;
		this.address = new Address("地名");
	}
	 
	public User clone(){
		try {
			return (User)super.clone();
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
	}
}

 

public class CloneTest {
 
	public static void main(String[] args) {
	 
		User u1 = new User(29);
		 
		User u2 = u1.clone();
		 
		System.out.println(u1==u2);
		 
		System.out.println(u1.age == u2.age);
	 
	}
 
}

 

Object类的clone()方法虽然简单、易用,但它只是一种“潜克隆”——它只克隆该对象的所有Field值,不会对引用类型的Field值所引用的对象克隆。如果需要“深克隆”,则需要开发者自己进行“递归”克隆,保证所有引用类型的Field值所引用的对象都被复制了。

 

JAVA 7新增的Objects类(工具类),她提供了一些工具方法来操作对象,大多是“空指针”安全。

 

java为工具类的命名习惯是添加一个字母s,比如操作数组的工具类是Arrays,操作集合的工具类是Collections.

 

String类是不可变类,即一旦一个String对象被创建以后,包含在这个对象中的字符串序列是不可变的,直至这个对象被销毁。

 

StringBuffer对象则代表一个字符串序列可变的字符串;JDK1.5之后出现了StringBuilder类,两则的用法基本相同,但StringBuffer是线程安全的,StringBuilder则没有实现线程安全功能,所以性能略高。因此,如果需要创建一个内容可变的字符串对象,则应该优先考虑使用StringBuilder类。

 

StringBuilder、StringBuffer有两个属性:

length:表示包含的字符序列的长度,长度是可变的

capacity:表示对象的容量,通常capacity比length大,程序通常无须关心capacity属性。

 

Math类是一个工具类,它的构造器被定义成private,因此无法创建Math类的对象;Math类中的所有方法都是类方法,可以直接通过类名来调用它们。另外提供了两个静态Field:PI和E.

 

Calendar类中add(int field,int amount)与roll区别:

1、add()方法,如果需要增加某个字段值,则让amount为正数,如果要减少,则为负数

add当被修改的字段超出它允许的范围时,会发生进位,即上一级字段会增大。

如果下一级字段也需要改变,那么该字段会修正到变化最小的值

2、roll当被修改的字段超出它允许的范围时,上一级字段不会增大;下一级字段处理规则跟add相似。

 

Calendar有两种解释日历字段的模式:lenient模式和non-lenient模式,当Calendar处于lenient模式时,每个时间字段可接受超出它允许范围的值;当处于non-lenient模式时,如果为某个时间字段设置的值超出了它允许的范围,程序就会抛出异常。

 

set方法延迟修改

set(f,value)方法将日历字段f更改为value,此外,它还设置了一个内部成员变量,以指示日历字段f已经被更改了。尽管日历字段f是立即更改的,但是Calendar所代表的时间却不会立即修改,知道下次调用get()、getTime()、getTimeInMillis()、add()或roll()时才会重新计算日历时间。

public class LazyTest {
	public static void main(String[] args) {
		Calendar cal = Calendar.getInstance();
		cal.set(2003, 7, 31);//2003-7-31
		//将月份设为9,但9月31日不存在
		//如果立即修改,系统会把cal自动调整到10月31号
		cal.set(Calendar.MONTH, 8);
		//下面代码输出10月1号,Wed Oct 01 13:45:04 CST 2003
		//System.out.println(cal.getTime());
		cal.set(Calendar.DATE, 5);
		//下面输出9月5号;Fri Sep 05 13:46:18 CST 2003
		System.out.println(cal.getTime());
	}
 
}

 

TimeZone设置程序中时间所属的时区,其中TimeZone就代表了时区。

TimeZone是一个抽象类,不能调用其构造器来创建实例,但可以调用静态方法:getDefault()或getTimeZone()得到TimeZone实例,其中getDefault()方法用于获得运行机器上的默认时区,默认时区可以通过修改操作系统的相关配置来调整;getTimeZone()则根据时区ID来获取对应的时区

public class TestTimeZone
{
	public static void main(String[] args) 
	{
		//取得Java所支持的所有时区ID
		String[] ids = TimeZone.getAvailableIDs();
		System.out.println(Arrays.toString(ids));
		TimeZone my = TimeZone.getDefault();
		//获取系统默认时区的ID:Asia/Shanghai
		System.out.println(my.getID());
		//获取系统默认时区的名称:中国标准时间
		System.out.println(my.getDisplayName());
		//获取指定ID的时区的名称:纽芬兰标准时间
		System.out.println(TimeZone.getTimeZone("CNT").getDisplayName());
	}
}

 

 

运行结果:

[....]

Asia/Shanghai

中国标准时间

纽芬兰标准时间

 

 

java国际化主要通过三个类完成:

1、java.util.ResourceBundle:用于加载国家、语言资源包。

2、java.util.Locale:用于封装特定的国家/区域、语言环境

3、java.text.MessageFormat:用于格式化带占位符

 

将非西欧字符转为unicode编码

native2ascii mess.properties mess_zh_CN.properties

 

如果系统同时存在资源文件、类文件,系统将以类文件为主,而不会调用资源文件。对于简体中文的Locale,ResourceBundle搜索资源文件的顺序是:

1、baseName_zh_CN.class

2、baseName_zh_CN.properties

3、baseName_zh.class

4、baseName_zh.properties

5、baseName.class

6、baseName.properties

系统按照上面的顺序搜索资源文件,如果一直找不到则系统会抛出异常

 

使用属性文件简单、快捷,但有时候我们希望以类文件作为资源文件,java允许使用类文件代替资源文件,即将所有的key-value对存入class文件,而不是属性文件。

使用类文件来代替资源文件必须满足如下条件:

1、类的名字必须为baseName_language_country,这个属性文件的命名相似。

2、该类必须继承ListResourceBundle,并重写getContents()方法,该方法返回Object数组,该数组的每一项都是key-value对。

 

public class myMess_zh_CN extends ListResourceBundle{
	//定义资源
	private final Object myData[][]={
		{"msg","{0},你好!今天日期是{1}"},
		{"msg1","{0},你好!今天日期是{1}"}
	};
	 
	//重写getContents()方法
	@Override
	protected Object[][] getContents() {
		return myData;
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值