think in java 学习笔记

来源:互联网 发布:大狗狗影视 域名 编辑:程序博客网 时间:2024/04/29 22:24

总的感觉是java比c++根具有安全性,这是其最大的特点,当然这就得失去必要的性能了。

1。一句话巧计运算顺序

“Ulcer Addicts Really Like C A lot”,即“溃疡患者特别喜欢(维生素)C”。
助记词 运算符类型 运算符
Ulcer(溃疡) Unary:一元 + - + + - [[ 其余的 ]]
Addicts(患者) Arithmetic(shift);算术(和移位) * / % + - << >>
Really(特别) Relational:关系 > < >= <= == !=
Like(喜欢) Logical(bitwise):逻辑(和按位) && || & | ^
C Conditional(ternary):条件(三元) A>B ? X:Y
A Lot Assignment:赋值 =(以及复合赋值,如*=)
当然,对于移位和按位运算符,上表并不是完美的助记方法;但对于其他运算来说,它确实很管用。

 

2 算术运算中容易出现的溢出错误

//: Overflow.java
// Surprise! Java lets you overflow.
public class Overflow {
public static void main(String[] args) {
int big = 0x7fffffff; // max int value
prt("big = " + big);
int bigger = big * 4;
prt("bigger = " + bigger);
}
static void prt(String s) {
System.out.println(s);
}
} ///:~
输出结果如下:
big = 2147483647
bigger = -4

编译器不会有出错提示,运行时也不会出现异常反应。爪哇咖啡(Java)确实是很好的东西,
但却没有“那么”好!

 

3 java的 标签  这是C++的循环控制所没有的特性

 label1:
外部循环{
内部循环{
//...
break; //1
//...
continue; //2
//...
continue label1; //3
//...
break label1; //4
}
}
在条件1 中,break 中断内部循环,并在外部循环结束。在条件2 中,continue 移回内部循环的起始处。但
在条件3 中,continue label1 却同时中断内部循环以及外部循环,并移至label1 处。随后,它实际是继续
循环,但却从外部循环开始。在条件4 中,break label1 也会中断所有循环,并回到label1 处,但并不重
新进入循环。也就是说,它实际是完全中止了两个循环。

 

4 Math.random() 产生的数的范围是[0,1)

 

5.关于static

 static 的含义
理解了this 关键字后,我们可更完整地理解static(静态)方法的含义。它意味着一个特定的方法没有
this。我们不可从一个static 方法内部发出对非static 方法的调用(注释②),尽管反过来说是可以的。
而且在没有任何对象的前提下,我们可针对类本身发出对一个static 方法的调用。事实上,那正是static
方法最基本的意义。它就好象我们创建一个全局函数的等价物(在C 语言中)。除了全局函数不允许在Java
中使用以外,若将一个static 方法置入一个类的内部,它就可以访问其他static 方法以及static 字段。
②:有可能发出这类调用的一种情况是我们将一个对象句柄传到static 方法内部。随后,通过句柄(此时实
际是this),我们可调用非static 方法,并访问非static 字段。但一般地,如果真的想要这样做,只要制
作一个普通的、非static 方法即可。

 

6.java的垃圾收集的关键两点

a垃圾收集并不等于“破坏”

假定我们的对象分配了一个“特殊”内存区域,没
有使用new。垃圾收集器只知道释放那些由new 分配的内存,所以不知道如何释放对象的“特殊”内存。为
解决这个问题,Java 提供了一个名为finalize()的方法,可为我们的类定义它。在理想情况下,它的工作原
理应该是这样的:一旦垃圾收集器准备好释放对象占用的存储空间,它首先调用finalize(),而且只有在下
一次垃圾收集过程中,才会真正回收对象的内存。

b我们的对象可能不会当作垃圾被收掉

有时可能发现一个对象的存储空间永远都不会释放,因为自己的程序永远都接近于用光空间的临界点。若程
序执行结束,而且垃圾收集器一直都没有释放我们创建的任何对象的存储空间,则随着程序的退出,那些资
源会返回给操作系统。这是一件好事情,因为垃圾收集本身也要消耗一些开销。如永远都不用它,那么永远
也不用支出这部分开销

 

7java 中对象的创建过程

在这里有必要总结一下对象的创建过程。请考虑一个名为Dog 的类:
(1) 类型为Dog 的一个对象首次创建时,或者Dog 类的static 方法/static 字段首次访问时,Java 解释器
必须找到Dog.class(在事先设好的类路径里搜索)。
(2) 找到Dog.class 后(它会创建一个Class 对象,这将在后面学到),它的所有static 初始化模块都会运
行。因此,static 初始化仅发生一次——在Class 对象首次载入的时候。
(3) 创建一个new Dog()时,Dog 对象的构建进程首先会在内存堆(Heap)里为一个Dog 对象分配足够多的存
储空间。
(4) 这种存储空间会清为零,将Dog 中的所有基本类型设为它们的默认值(零用于数字,以及boolean 和
char 的等价设定)。
(5) 进行字段定义时发生的所有初始化都会执行。
(6) 执行构建器。正如第6 章将要讲到的那样,这实际可能要求进行相当多的操作,特别是在涉及继承的时
候。

8 java的数组

Java的一项主要设计目标就是安全性。所以在C和C++里困扰程序员的许多问题都未在Java里重复。一个Java可以保证被初始化,而且不可在它的范围之外访问。由于系统自动进行范围检查,所以必然要付出一些代价:针对每个数组,以及在运行期间对索引的校验,都会造成少量的内存开销。但由此换回的是更高的安全性,以及更高的工作效率。为此付出少许代价是值得的。
创建对象数组时,实际创建的是一个句柄数组。而且每个句柄都会自动初始化成一个特殊值,并带有自己的关键字:null(空)。一旦Java看到null,就知道该句柄并未指向一个对象。正式使用前,必须为每个句柄都分配一个对象。若试图使用依然为null的一个句柄,就会在运行期报告问题。因此,典型的数组错误在Java里就得到了避免。

9 应当熟习的矩阵构造

a:

int[][][] a3 = new int[pRand(7)][][];
121
for(int i = 0; i < a3.length; i++) {
a3[i] = new int[pRand(5)][];
for(int j = 0; j < a3[i].length; j++)
a3[i][j] = new int[pRand(5)];
}

b:

Integer[][] a5;
a5 = new Integer[3][];// 分配的只是句柄而已
for(int i = 0; i < a5.length; i++) {
a5[i] = new Integer[3];
for(int j = 0; j < a5[i].length; j++)
a5[i][j] = new Integer(i*j);// 真正的指向一个对象
}

 

10 记得你安装java时设置的CLASSPATH吧 现在告诉你它是怎么工作的

//: LibTest.java
// Uses the library
package c05;
import com.bruceeckel.util.*;
public class LibTest {
public static void main(String[] args) {
Vector v = new Vector();
List l = new List();
}
} ///:~
编译器遇到import 语句后,它会搜索由CLASSPATH 指定的目录,查找子目录com/bruceeckel/util,然后查
找名称适当的已编译文件(对于Vector 是Vector.class,对于List 则是List.class)。注意Vector 和
List 内无论类还是需要的方法都必须设为public。

 

11java的接口访问机制

使用public 关键字时,它意味着紧随在public 后面的成员声明适用于所有人,特别是适用于使用库的客户
程序员。假定我们定义了一个名为dessert 的包,其中包含下述单元
//: Cookie.java
// Creates a library
package c05.dessert;
public class Cookie {
public Cookie() {
System.out.println("Cookie constructor");
}
void foo() { System.out.println("foo"); }
} ///:~
请记住,Cookie.java 必须驻留在名为dessert 的一个子目录内,而这个子目录又必须位于由CLASSPATH 指
定的C05 目录下面(C05 代表本书的第5 章)。不要错误地以为Java 无论如何都会将当前目录作为搜索的起
点看待。如果不将一个“.”作为CLASSPATH 的一部分使用,Java 就不会考虑当前目录。
现在,假若创建使用了Cookie 的一个程序,如下所示:
//: Dinner.java
// Uses the library
import c05.dessert.*;
public class Dinner {
public Dinner() {
System.out.println("Dinner constructor");
}
public static void main(String[] args) {
Cookie x = new Cookie();
//! x.foo(); // Can't access
}
} ///:~
就可以创建一个Cookie 对象,因为它的构建器是public 的,而且类也是public 的(公共类的概念稍后还会
进行更详细的讲述)。然而,foo()成员不可在Dinner.java 内访问,因为foo()只有在dessert 包内才是
“友好”的。

 

private 不能接触!
private 关键字意味着除非那个特定的类,而且从那个类的方法里,否则没有人能访问那个成员。同一个包
内的其他成员不能访问private 成员,这使其显得似乎将类与我们自己都隔离起来。另一方面,也不能由几
个合作的人创建一个包。所以private 允许我们自由地改变那个成员,同时毋需关心它是否会影响同一个包
内的另一个类。默认的“友好”包访问通常已经是一种适当的隐藏方法;请记住,对于包的用户来说,是不
能访问一个“友好”成员的。这种效果往往能令人满意,因为默认访问是我们通常采用的方法。对于希望变
成public(公共)的成员,我们通常明确地指出,令其可由客户程序员自由调用。而且作为一个结果,最开
始的时候通常会认为自己不必频繁使用private 关键字,因为完全可以在不用它的前提下发布自己的代码
(这与C++是个鲜明的对比)。然而,随着学习的深入,大家就会发现private 仍然有非常重要的用途,特
别是在涉及多线程处理的时候(详情见第14 章)。
下面是应用了private 的一个例子:
//: IceCream.java
// Demonstrates "private" keyword
class Sundae {
private Sundae() {}
static Sundae makeASundae() {
return new Sundae();
}
}
public class IceCream {
public static void main(String[] args) {
//! Sundae x = new Sundae();
Sundae x = Sundae.makeASundae();
133
}
} ///:~
这个例子向我们证明了使用private 的方便:有时可能想控制对象的创建方式,并防止有人直接访问一个特
定的构建器(或者所有构建器)。在上面的例子中,我们不可通过它的构建器创建一个Sundae 对象;相反,
必须调用makeASundae()方法来实现(注释③)。
③:此时还会产生另一个影响:由于默认构建器是唯一获得定义的,而且它的属性是private,所以可防止
对这个类的继承(这是第6 章要重点讲述的主题)。
若确定一个类只有一个“助手”方法,那么对于任何方法来说,都可以把它们设为private,从而保证自己
不会误在包内其他地方使用它,防止自己更改或删除方法。