1. 构造器
- 构造器的一个重要的作用: 保证对象被使用之前初始化了.
- 构造器是一种特殊类型的方法,因为他没有返回值。这与返回值为空(void)明显不同。对于空返回值,尽管方法本身不会自动返回什么, 但仍可选择让他返回别的东西。
- 思考: void还可以返回别的东西? 是什么东西呢? 后来想到,可能是void可以通过return ;返回. 也就是可以截断下面的流程. 而构造函数不可以,他必须将其全部执行完毕才能退出方法.? return; 就是返回void的.
?2. 方法重载
- 方法重载的条件
- 基本类型重载的问题
- 基本类型能从一个“较小”的类型自动提升至一个“较大“的类型. 此过程一旦涉及到重载, 可能会出现混淆。看下面这个例子
package net.mindview.initialization;
import static net.mindview.util.Print.*;
public class PrimitiveOverloading {
void f1(char x) {print("f1(char)");}
byte x) {print(f1(byte)short x) {print(f1(short)int x) {print(f1(int)long x) {print(f1(long)float x) {print(f1(float)double x) {print(f1(double));}
void f2(f2(byte)f2(short)f2(int)f2(long)f2(float)f2(double)void f3(f3(short)f3(int)f3(long)f3(float)f3(double)void f4(f4(int)f4(long)f4(float)f4(double)void f5(f5(long)f5(float)f5(double));}
void f6(f6(float)f6(double)void f7(f7(double)/**测试常量*/
void testConstVal(){
print(5:);
f1(5);f2(5);f3(5);f4(5);f5(5);f6(5);f7(5);println("");
}
*测试char testChar(){
char x = 'x';
print(char:);
f1(x);f2(x);f3(x);f4(x);f5(x);f6(x);f7(x);println(*测试byte testByte(){
byte x = 0byte:*测试Short testShort(){
short x = short:*测试Int testInt(){
int x = int:*测试long testLong(){
long x = long:*测试double testDouble(){
double x = double:static main(String[] args) {
PrimitiveOverloading p = new PrimitiveOverloading();
p.testConstVal();
p.testChar();
p.testByte();
p.testShort();
p.testInt();
p.testLong();
p.testDouble();
}
}
执行结果:
5:f1(int)f2(int)f3(int)f4(int)f5(long)f6(float)f7(double)
char:f1(char)f2(byte:f1(byte)f2(byte)f3(short)f4(short:f1(short)f2(short)f3(int:f1(long:f1(long)f2(long)f3(long)f4(long)f5(double:f1(double)f2(double)f3(double)f4(double)f5(double)f6(double)f7(double)
结论: 有int, 则执行对应的int方法, 如果没有, 则向上转型,执行最近的方法, 其他char,byte,short,int,long,double都是如此. 其中char有所不同,如果无法找到恰好是接收char参数的方法,就会把char提升至int值.
- 如果参数是一个较大的类型,就需要通过强转为一个较小的类型后才能使用,否则,编译报错.
- 为何不能以返回值来区分方法的重载
4. this关键字
5. 垃圾回收器
- 垃圾回收器负责回收对象占用的内存资源。
- 垃圾回收器也有不能回收的“特殊的”内存资源。假定你的对象获得了一个“特殊”的内存资源, 由于垃圾回收器只知道负责释放那些经由new分配的内存, 所以他不知道该如何释放该对象的这块“特殊”内存。为了应对这种情况,java允许在类中定义一个名为finalize()的方法。
- finalize()方法的工作原理"假定"是这样:一旦垃圾回收器准备好释放对象占用的存储空间,将首先调用?finalize()方法,并且在下一次垃圾回收动作发生时,才会真正回收对象占用的内存。所以你要打算调用finalize(),就能在垃圾回收时做一些重要的清理工作。
- 垃圾回收只与内存有关:
- java里的垃圾并不总是被垃圾回收, 调用了finalize()方法, 也不一定会立即生效, 这时垃圾处理机制决定的。 通常只有内存濒临耗完时才会调用垃圾回收机制。finalize()方法才会最终生效. 因为垃圾回收本身也会消耗资源.
- 普通的清理工作不适合finalize()
- 通常类中不必定义finalize()方法来主动销毁对象. 只有一种情况需要finalize(),即通过某种创建对象方式以外的方式为对象分配存储空间。可我们都知道, java中一切接对象,那么这种“特殊”情况又是怎么回事呢?
- 这种情况通常发生在java的"本地方法"的情况。本地方法是一种在java中调用非java代码的方式。
- finalize()的用武之地:对象终结条件的验证。
- 对象终结条件是怎么回事呢? 当一个对象没有用的时候,也就是他应该被清理的时候。这个对象应该处于某种状态, 让他占用的内存完全被安全地释放。例如:对象代表了打开文件, 当对象被回收前,程序员应该关闭打开的这个文件。那么,如果,一个文件被打开了, 却没有被关闭, 这样就会导致垃圾回收器不能回收这块资源。久而久之就会导致内存的溢出。 这是程序的缺陷。 这时如果在垃圾回收的时候执行了finalized()方法,这个缺陷就可能会被发现,具体看下面的例子。
package net.mindview.initialization;
Book{
boolean checkedOut = false;
Book(boolean checkedOut){
this.checkedOut = checkedOut;
}
checkIn(){
checkedOut = ;
}
protected finzlized() throws Throwable {
if(checkedOut){
System.out.println(有书被借走但未归还 );
//基类版本的finalize()也要做一些重要的事,应使用super来调用.
super.finalize();
}
}
}
TerminationCondition {
main(String[] args) {
Book novel = new Book(true);
合理的清理
novel.checkIn();
书被借出后,没有归还
强制垃圾回收并且执行finalized方法
System.gc();
}
}
本例的总结条件,应该是,被签出的图书全部被签入.也就是说借出的书应该全部被归还. 但在main方法中,程序员错误的将图书借出了,但此书未被归还。但程序却没有任何错误。 这种问题一旦存在了, 很难被程序员自己发现。 直到最后内存溢出,调用finalize()方法,我们才知道。这里finalize就是用来验证终结条件的。
- 再解释一下上面的案例: 一个对象能够被清理, 条件是没有地方在使用它了。 如果一个对象是打开文件, 使用了, 就应该关闭文件, 如果没有关系, 这个对象就不能被回收,久而久之必然导致内存的耗尽,jvm就会调用垃圾回收期回收对象。这时如果程序员手动定义了finalize()方法,那么当垃圾回收时,他就会发现内存溢出的原因在哪里了。所以, 在某种情况下定义finalize()方法是一个好的喜欢.
6. 成员初始化
- 类成员
- 基本类型的成员变量,如果在定义的时候没有初始化,系统会自动初始化为对应类型的默认值.
- 对象应用类型如果在定义的时候没有被初始化,此引用就会获得一个特殊的值null.
7.构造器初始化
8. 可变参数列表
NewVarArgs {
printArray(Object ... args){
for(Object arg: args) {
System.out.print(arg + );
}
System.);
}
main(String[] args) {
printArray(new Integer(47),new Float(3.14),1)">new Double(2.333));
printArray((Object[])new Integer[]{1,2,1)">3,1)">4});
printArray();
}
}
?
- 使用 ...的方式定义可变数组
- 当指定参数时,编译器实际上会自动填充为一个数组,你获取的仍旧是一个数组, 因此可以再方法内部使用foreach循环打印
- 当参数本身就是一个数组时, 编译器直接接受这个数组
- 可变参数必须是方法的最后一个参数
- 可变参数可以和自动包装机制和谐相处。
- 参数是Integer类型, 如果换地过来的是int类型, 可以自动转换
- 可变参数的重载
- 可变参数会使用自动包装机制来匹配重载方法, 然后调用最明确匹配的方法。
9. 枚举类型
?
enum Spiciness {
NOT,MILD,MEDIUM,HOT,FALMING
}
SimpleEnumUse {
main(String[] args) {
Spiciness falming = Spiciness.FALMING;
System.out.println(falming);
}
}
?
- 枚举定义使用enum关键字
- 枚举类型的实例是常量,所以命名要求全部大写.
- 在创建enum时,编译器会自动添加一些使用的特性.?
- 自动创建toSring()方法,以便可以很方便的显示enum实例的名字,这正是上面可以产生其输出答案的原因。
- 自动生成oridinal()方法: 用来表示enum常量声明的顺序
- 自动生成static value()方法:按照enum生成的顺序,产生有这些常量构成的数组.
(Spiciness s: Spiciness.values()){
System.out.println(s + ," + s.ordinal());
}
}
}
?
- enum是在有限的集合中进行选择,因此其与switch是绝佳组合.
main(String[] args) {
Burrito plain = Burrito(Spiciness.HOT);
Burrito greenChile = Burrito(Spiciness.MEDIUM);
Burrito jalapeno = Burrito(Spiciness.NOT);
plain.describe();
greenChile.describe();
jalapeno.describe();
}
}
Burrito {
Spiciness degree;
Burrito(Spiciness degree){
this.degree = degree;
}
describe(){
switch(degree){
case NOT:
System.not);
break;
MILD:
MEDIUM:
System.medium HOT:
System.hot FALMING:
default:
System.falming;
}
}
}
?
-
?
?
?
?
?
? (编辑:北几岛)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|