1、基础类型的方法重载,依然按原来的重载规则,用类别进行识别,但是在没有申明类型时如3则默认为int型,碰到参数值小于自变量时会自动进行类型转换,碰到参数值大于自变量是要进行强制类型转换才可以。
2、涉及到基础类型的方法重载,建议直接用包装器就好。
3、构建器适合特殊初始化,一般初始化还是用全局变量初始化比较好,最好这样定义所有的类成员,然后在构造方法中对需要特殊初始化的类成员进行特俗初始化。
4、对象的初始化顺序:类中包括:成员变量、构造器、方法三个部分,其中成员变量又包括静态成员变量与非静态成员变量。当新建一个类的对象时,会首先初始化静态成员变量(注意静态成员只在类第一次实例化时初始化仅有的一次),然后初始化非静态成员变量(实例化一次,就初始化一次),然后执行对应的构建器进行构建器初始化,最后如果有调用方法(无论静态还是非静态方法),则对方法中的局部变量进行初始化(如果是静态方法,则会对调用的静态变量进行初始化)。此外如果第一次直接调用类中的静态变量,自认也会对静态成员变量进行唯一的一次初始化。
5、由static包裹的区域为静态初始块,里面的变量都可以认为是静态的。
6、如果存在父类的情况,如果要实例化子类,那肯定会初始化父类后,才会初始化子类。因为有父才有子。
7、数组也是一个对象,也适合对象句柄的概念。
8、数组会进行自动初始化。
9、多维数组可以理解为数组的数组。
10、选择合成还是选在继承,合成是是用于描述对象间的“包含”关系,继承是用来描述对象间的“属于”关系。如果要用几个对象去构造一个新对象则用合成,如果是一个对象时抽象的,其下还有多个具体的对象,为了方便拓展则采用“属于”关系会更合适。
11、对应final最好再定义的时候就进行初始化。
12、final类型的类成员变量,不会在类加载时自动进行初始化,而是在构造器中即第一次实例化时进行初始化,而且必须在构造器中进行初始化。
13、只有在方法的代码量非常少,或者想明确禁止方法被覆盖的时候,才应考虑将一个方法设为final。
14、类内所有private 方法都自动成为final。
15、final数据的话,对于基本类型则值不可改变,对于对象则是对象句柄指向的对象不可改变但对象可以改变。final方法的话则方法不可被重写,private的方法自动具有final的方法的特性,因为private的方法外界无法访问,自然也不能进行覆盖。final类的话,则类不可被继承,final类中的数据可以被修改,当final类中的所有方法自动都是final方法,因为类不可被继承,自然类中的方法不可被重写。
16、类的初始化顺序,如果在一个类中则:静态初始化(包括方法和变量)--》成员初始化(包括方法和变量)--》构造器初始化--》方法调用初始化
如果存在继承则:父类静态初始化(包括方法和变量)--》子类静态初始化(包括方法和变量)--》父类成员初始化(包括方法和变量)--》父类构造器初始化--》子类成员初始化(包括方法和变量)--》子类构造器初始化
17、为什么要把一个方法声明成final 呢?正如上一章指出的那样,它能防止其他人覆盖那个方法。但也许更重
要的一点是,它可有效地“关闭”动态绑定,或者告诉编译器不需要进行动态绑定。这样一来,编译器就可
为final 方法调用生成效率更高的代码。
18、接口中的成员变量是static final的并且不能采用空白final进行初始化。
19、若想在除外部类非static 方法内部之外的任何地方生成内部类的一个对象,必须将那个对象的类型设为“外部类名.内部类名”。
20、如果是两个不同的对象则不存在线程同步的问题,因为两个对象在内存中是分离的,不互相影响,如果是同一个对象并且存在多线程就
存在线程同步的问题,因为各个线程共享同一个内存,这就有可能出现问题。
21、若试图定义一个匿名内部类,并想使用在匿名内部类外部定义的一个对象,则编译器要求外部对象为final属性。
22、“创建从Contents 衍生出来的匿名类的一个对象。
23、由于它是匿名的,没有名字赋给构建器,所以我们不能拥有一个构建器。
24、因此,为了在散列表中将自己的类作为键使用,必须同时覆盖hashCode()和equals()。
25、这种除非绝对必要,否则就不采取行动的方法叫作“懒惰求值”。
26、换言之,用于一个特定方法的“违例规范接口”可能在继承和覆盖时变得更“窄”,但它不会变得更“宽”——这与继承时的类接口规
则是正好相反的。
27、对违例来说,一项特别的设计问题是决定在这一级完全控制一个违例,还是进行部分控制,并传递相同(或不同)的违例,或者只是简
单地传递它。在适当的时候,简单地传递可极大简化我们的编码工作。
28、用违例做下面这些事情:
(1) 解决问题并再次调用造成违例的方法。
(2) 平息事态的发展,并在不重新尝试方法的前提下继续。
(3) 计算另一些结果,而不是希望方法产生的结果。
(4) 在当前环境中尽可能解决问题,以及将相同的违例重新“掷”出一个更高级的环境。
(5) 在当前环境中尽可能解决问题,以及将不同的违例重新“掷”出一个更高级的环境。
(6) 中止程序执行。
(7) 简化编码。若违例方案使事情变得更加复杂,那就会令人非常烦恼,不如不用。
(8) 使自己的库和程序变得更加安全。这既是一种“短期投资”(便于调试),也是一种“长期投资”(改
善应用程序的健壮性)
29、对一种特殊的资源——对象中的内存——Java 提供了内建的机制来防止它们的冲突。由于我们通常将数据元
素设为从属于private(私有)类,然后只通过方法访问那些内存,所以只需将一个特定的方法设为
synchronized(同步的),便可有效地防止冲突。在任何时刻,只可有一个线程调用特定对象的一个
synchronized 方法(尽管那个线程可以调用多个对象的同步方法)。
每个对象都包含了一把锁(也叫作“监视器”),它自动成为对象的一部分(不必为此写任何特殊的代
码)。调用任何synchronized 方法时,对象就会被锁定,不可再调用那个对象的其他任何synchronized 方
法,除非第一个方法完成了自己的工作,并解除锁定。在上面的例子中,如果为一个对象调用f(),便不能
再为同样的对象调用g(),除非f()完成并解除锁定。因此,一个特定对象的所有synchronized 方法都共享
着一把锁,而且这把锁能防止多个方法对通用内存同时进行写操作(比如同时有多个线程)。
每个类也有自己的一把锁(作为类的Class 对象的一部分),所以synchronized static 方法可在一个类的
范围内被相互间锁定起来,防止与static 数据的接触。
30、所以必须记住一个重要的规则:对于访问某个关键共享资源的所有方
法,都必须把它们设为synchronized,否则就不能正常地工作。
31、现在又遇到了一个新问题。Watcher2 永远都不能看到正在进行的事情,因为整个run()方法已设为“同
步”。而且由于肯定要为每个对象运行run(),所以锁永远不能打开,而synchTest()永远不会得到调用。之
所以能看到这一结果,是因为accessCount 根本没有变化。
为解决这个问题,我们能采取的一个办法是只将run()中的一部分代码隔离出来。想用这个办法隔离出来的
那部分代码叫作“关键区域”,而且要用不同的方式来使用synchronized 关键字,以设置一个关键区域。
Java 通过“同步块”提供对关键区域的支持;这一次,我们用synchronized 关键字指出对象的锁用于对其
中封闭的代码进行同步。如下所示:
synchronized(syncObject) {//syncObject就是共享资源的所属对象
// This code can be accessed by only
// one thread at a time, assuming all
// threads respect syncObject's lock
}
在能进入同步块之前,必须在synchObject 上取得锁。如果已有其他线程取得了这把锁,块便不能进入,必
须等候那把锁被释放。
当然,所有同步都取决于程序员是否勤奋:要访问共享资源的每一部分代码都必须封装到一个适当的同步块
里。
所以假如已知一个方法不会造成冲突,最明智的做法便是撤消其中的synchronized 关键字。
32、无论什么时候创建了一个Bean,就必须假定它要在一个多线程的环境中运行。
只要可行,Bean 的所有公共方法都应同步。
如果将一个多造型事件送给一系列对那个事件感兴趣的“听众”,必须假在列表中移动的时候可以添加
或者删除。
33、synchronized 不能继承
34、(1) 新(New):线程对象已经创建,但尚未启动,所以不可运行。
(2) 可运行(Runnable ):意味着一旦时间分片机制有空闲的CPU 周期提供给一个线程,那个线程便可立即
开始运行。因此,线程可能在、也可能不在运行当中,但一旦条件许可,没有什么能阻止它的运行——它既
没有“死”掉,也未被“堵塞”。
(3) 死(Dead):从自己的run()方法中返回后,一个线程便已“死”掉。亦可调用stop()令其死掉,但会
产生一个违例——属于Error 的一个子类(也就是说,我们通常不捕获它)。记住一个违例的“掷”出应当
是一个特殊事件,而不是正常程序运行的一部分。所以不建议你使用stop()(在Java 1.2 则是坚决反
对)。另外还有一个destroy()方法(它永远不会实现),应该尽可能地避免调用它,因为它非常武断,根
本不会解除对象的锁定。
(4) 堵塞(Blocked):线程可以运行,但有某种东西阻碍了它。若线程处于堵塞状态,调度机制可以简单地
跳过它,不给它分配任何CPU 时间。除非线程再次进入“可运行”状态,否则不会采取任何操作。
35、如果一个对象有两个synchronized方法,并其中一个调用另一个方法,则锁机制不会影响,第一个方法对第二个的调用,并且第一个方
法执行完后,释放锁。
36、一个线程被suspend的,则需要另一个线程通过调用被suspend线程对象的resure进行唤醒操作。
对于Java 1.2,大家应注意suspend()和resume()已获得强烈反对,因为suspend()包含了对象锁,不但suspend线程,而且线程对象的锁也被
suspend,除非被唤醒,否则锁不会释放,所以极易出现“死锁”现象。换言之,很容易就会看到许多被锁住的对象在傻乎乎地等待对方。这
会造成整个应用程序的“凝固”。
37、我们知道无论sleep()还是suspend()都不会在自己被调用的时候解除锁定,在另一方面,wait()方法在被调用时却会解除锁定,这意味
着可在执行wait()期间调用线程对象中的其他同步方法。
38、我们也可以看到wait()的两种形式。第一种形式采用一个以毫秒为单位的参数,它具有与sleep()中相同的
含义:暂停这一段规定时间。区别在于在wait()中,对象锁已被解除,而且能够自由地退出wait(),因为一
个notify() 可强行使时间流逝。
第二种形式不采用任何参数,这意味着wait()会持续执行,直到notify()介入为止。而且在一段时间以后,
不会自行中止。
39、事实上,我们能调用wait()的唯一地方是在一个同步的方法或代码块内部。若在一个不同步的方法内调用
wait()或者notify(),尽管程序仍然会编译,但在运行它的时候,就会得到一个
IllegalMonitorStateException(非法监视器状态违例),而且会出现多少有点莫名其妙的一条消息:
“current thread not owner”(当前线程不是所有人”。注意sleep(),suspend()以及resume()都能在不
同步的方法内调用,因为它们不需要对锁定进行操作。
40、若必须等候其他某些条件(从线程外部加以控制)发生变化,同时又不想在线程内一直傻乎乎地等下去,一
般就需要用到wait()。
41、但在测试模型中,会设置一个管道化的数据流,使两个线程相互间能安全地传递数据(这正是使用管道流的目的)。
Sender 将数据置入Writer,并“睡眠”随机长短的时间。然而,Receiver 本身并没有包括sleep(),
suspend()或者wait()方法。但在执行read()的时候,如果没有数据存在,它会自动进入“堵塞”状态。
42、由于线程可能进入堵塞状态,而且由于对象可能拥有“同步”方法——除非同步锁定被解除,否则线程不能
访问那个对象——所以一个线程完全可能等候另一个对象,而另一个对象又在等候下一个对象,以此类推。
这个“等候”链最可怕的情形就是进入封闭状态——最后那个对象等候的是第一个对象!此时,所有线程都
会陷入无休止的相互等待状态,大家都动弹不得。我们将这种情况称为“死锁”。尽管这种情况并非经常出
现,但一旦碰到,程序的调试将变得异常艰难。
43、所以应尽量避免使用stop(),应该采用Blocking.java 那样的方法,用一个标志告诉线程什么时候通过退出自己的run()方法来中止自己
的执行。。但在这些情况下,我们仍然不该使用stop(),而应换用由Thread 提供的interrupt()方法,以便中止并退出堵塞的代码。
44、若标志指出线程应该挂起,便用wait()命其进入等待状态。若标志指出线程应当恢复,则用一个
notify()重新启动线程。
45、线程的优先级(Priority)告诉调试程序该线程的重要程度有多大。如果有大量线程都被堵塞,都在等候运
行,调试程序会首先运行具有最高优先级的那个线程。然而,这并不表示优先级较低的线程不会运行(换言
之,不会因为存在优先级而导致死锁)。若线程的优先级较低,只不过表示它被准许运行的机会小一些而
已。
46、我们认为是由于“安全”或者“保密”方面的理由才使用线程组的。根据Arnold 和Gosling 的说法:
“线程组中的线程可以修改组内的其他线程,包括那些位于分层结构最深处的一个线程不能修改位于自己
所在组或者下属组之外的任何线程”(注释①)。
47、,线程的处理又多了一项新的
考虑因素:必须随时检查自己有没有“太多的线程”(无论对什么程序和运行平台)。若线程太多,必须试
着使用上面介绍的技术,对程序中的线程数量进行“平衡”。
48、(1) 对sleep,yield()以及/或者wait()的调用足够多吗?
(2) sleep()的调用时间足够长吗?
(3) 运行的线程数是不是太多?
(4) 试过不同的平台和JVM 吗?
49、何时使用多线程技术,以及何时避免用它,这是我们需要掌握的重要课题。骼它的主要目的是对大量任务进
行有序的管理。通过多个任务的混合使用,可以更有效地利用计算机资源,或者对用户来说显得更方便。资
源均衡的经典问题是在IO 等候期间如何利用CPU。至于用户方面的方便性,最经典的问题就是如何在一个长
时间的下载过程中监视并灵敏地反应一个“停止”(stop )按钮的按下。
多线程的主要缺点包括:
(1) 等候使用共享资源时造成程序的运行速度变慢。
(2) 对线程进行管理要求的额外CPU 开销。
(3) 复杂程度无意义的加大,比如用独立的线程来更新数组内每个元素的愚蠢主意。
(4) 漫长的等待、浪费精力的资源竞争以及死锁等多线程症状。
线程另一个优点是它们用“轻度”执行切换(100 条指令的顺序)取代了“重度”进程场景切换(1000 条指
令)。由于一个进程内的所有线程共享相同的内存空间,所以“轻度”场景切换只改变程序的执行和本地变
量。而在“重度”场景切换时,一个进程的改变要求必须完整地交换内存空间。
多个线程可能共享同一个资源(比如一个对象里的内存),这是运用线程时面临的最大的一个麻烦。必须保
证多个线程不会同时试图读取和修改那个资源。这要求技巧性地运用synchronized(同步)关键字。
除此以外,运用线程时还要注意一个非常特殊的问题。由于根据Java 的设计,它允许我们根据需要创建任意
数量的线程——至少理论上如此(例如,假设为一项工程方面的有限元素分析创建数以百万的线程,这对
Java 来说并非实际)。然而,我们一般都要控制自己创建的线程数量的上限。因为在某些情况下,大量线程
会将场面变得一团糟,所以工作都会几乎陷于停顿。临界点并不象对象那样可以达到几千个,而是在100 以
下,或使用线程池。
50、这一优势是通过
PrintWriter 表现出来的,它有一个过载的构建器,能获取第二个参数——一个布尔值标志,指向是否在每
一次println()结束的时候自动刷新输出(但不适用于print()语句)。每次写入了输出内容后(写进
out),它的缓冲区必须刷新,使信息能正式通过网络传递出去。对目前这个例子来说,刷新显得尤为重要,
因为客户和服务器在采取下一步操作之前都要等待一行文本内容的到达。若刷新没有发生,那么信息不会进
入网络,除非缓冲区满(溢出),这会为本例带来许多问题。
编写网络应用程序时,需要特别注意自动刷新机制的使用。每次刷新缓冲区时,必须创建和发出一个数据包
(数据封)。就目前的情况来说,这正是我们所希望的,因为假如包内包含了还没有发出的文本行,服务器
和客户机之间的相互“握手”就会停止。换句话说,一行的末尾就是一条消息的末尾。但在其他许多情况
下,消息并不是用行分隔的,所以不如不用自动刷新机制,而用内建的缓冲区判决机制来决定何时发送一个
数据包。这样一来,我们可以发出较大的数据包,而且处理进程也能加快。
注意和我们打开的几乎所有数据流一样,它们都要进行缓冲处理。本章末尾有一个练习,清楚展现了假如我
们不对数据流进行缓冲,那么会得到什么样的后果(速度会变慢)。缓存可以减少资源的链接和断开次数,把主要时间用在传输数据,而不
是链接和断开上,从而有效的提高速度。
51、由于Java 的线程处理方式非常直接,所以让服务器控制多名客户并不是件难事。
最基本的方法是在服务器(程序)里创建单个ServerSocket,并调用accept()来等候一个新连接。一旦
accept()返回,我们就取得结果获得的Socket,并用它新建一个线程,令其只为那个特定的客户服务。然后
再调用accept() ,等候下一次新的连接请求。
52、如果我们换用数据报,就不必使用多线程了。用单个数据报即可“侦听”进入的所有数据报。一旦监视到有
进入的消息,程序就会进行适当的处理,并将答复数据作为一个数据报传回原先发出请求的那名接收者。若
数据报半路上丢失了,则用户会注意到没有答复数据传回,所以可以重新提交请求。
53、但是,用C 轻易就可以解决这个问题。因此,我们在这儿有机会学习将一个非Java 程序同Java 程序连接的最简便方
式。程序使用的Runtime 对象包含了一个名为exec()的方法,它会独立机器上一个独立的程序,并返回一个
Process(进程)对象。我们可以取得一个OutputStream,它同这个单独程序的标准输入连接在一起;并取
得一个InputStream,它则同标准输出连接到一起。要做的全部事情就是用任何语言写一个程序,只要它能
从标准输入中取得自己的输入数据,并将输出结果写入标准输出即可。如果有些问题不能用Java 简便与快速
地解决(或者想利用原有代码,不想改写),就可以考虑采用这种方法。亦可使用Java 的“固有方法”
(Native Method ),但那要求更多的技巧,大家可以参考一下附录A。
54、创建一个远程接口时,必须遵守下列规则:
(1) 远程接口必须为public 属性(不能有“包访问”;也就是说,它不能是“友好的”)。否则,一旦客户
583
试图装载一个实现了远程接口的远程对象,就会得到一个错误。
(2) 远程接口必须扩展接口java.rmi.Remote。
(3) 除与应用程序本身有关的违例之外,远程接口中的每个方法都必须在自己的throws 从句中声明
java.rmi.RemoteException。
(4) 作为参数或返回值传递的一个远程对象(不管是直接的,还是在本地对象中嵌入)必须声明为远程接
口,不可声明为实施类。
分享到:
相关推荐
在讨论Java编程思想学习笔记时,首先需要了解的是Java语言的平台无关性,而这一特性正是通过Java虚拟机(JVM)得以实现的。JVM作为Java程序设计的关键组成部分,对于Java开发人员来说是必须掌握的基础知识。在该学习...
### Java编程思想读书笔记 #### 一、Java与C++的区别及内存管理 在学习Java的过程中,我们常常会拿它与C++进行比较。这两门语言虽然有着相似之处,但也有许多不同点。 1. **内存管理:** - C++提供了更为底层的...
### Java编程思想学习笔记知识点详解 #### 一、操作符 **1.1 赋值操作符** - **符号**: `=` - **功能**: 用于将右侧的值赋给左侧的变量。 - **注意**: 当作用于基本类型时,赋值的是具体的值;当作用于对象时,则...
java编程思想的笔记。是别人的学习笔记。
读书笔记:java编程思想学习
《Java编程思想》是 Bruce Eckel 的经典之作,这本书深入浅出地介绍了Java语言的核心概念和技术,对于初学者和有经验的程序员来说都是极好的学习资源。以下是对书中的主要知识点进行的详细解读: 1. **Java语言基础...
JAVA学习笔记是面向对象编程语言的学习笔记,涵盖了JAVA的基本概念、面向对象编程思想、类和对象的概念、实例变量和局部变量的区别、方法的定义和调用、类型转换、精度问题、移位问题、switch语句的使用等内容。...
以上只是Java编程思想笔记中的冰山一角,深入学习还包括网络编程、数据库连接、JVM内存模型、垃圾回收机制、并发编程高级话题、Spring框架等内容。这些知识点构成了Java开发者必备的基础知识体系,通过不断学习和...
《Java编程思想笔记》是基于 Bruce Eckel 的经典著作 "Thinking in Java" 所做的学习总结,这本书深入浅出地介绍了Java语言的核心概念和技术。在本文中,我们将围绕Java编程的一些关键知识点进行深入探讨,包括但不...
Java JDK 6学习笔记是为Java初学者量身定制的一份宝贵资料,它涵盖了Java编程的基础概念、语法以及核心特性。这份PPT简体版旨在帮助读者快速掌握Java开发的基本技能,逐步成为一名合格的Java程序员。 Java JDK...
### JAVA编程思想笔记 #### 一、编程语言与Java特性 1. **编程语言类别**: - **机器语言**:直接与硬件交互的语言,由0和1组成。 - **汇编语言**:接近机器语言,使用助记符表示指令。 - **高级语言**:更接近...
读书笔记:学习Java编程思想
对于那些想要提升Java编程技能的开发者来说,这本书是不可多得的参考资料。 总的来说,《Java JDK 8学习笔记》是一本全面覆盖Java 8新特性的指南,它通过深入浅出的讲解和丰富的实例,帮助读者掌握Java 8的核心概念...
从标题“java核心思想读书笔记”和描述可以看出,这份资料是作者结合《Java核心思想》一书和其他网络资源整理而成,适合不同水平的Java学习者,特别是初学者和有经验的工程师。 1. **Java的设计目标** - 不同于...
### Java编程思想笔记知识点概述 #### 第 1 章 对象导论 在这一章节中,主要介绍...以上内容概括了《Java编程思想笔记》中的核心知识点,涵盖了Java语言的基础到高级特性,适合初学者和有一定经验的开发者参考学习。