【java】Head First Java笔记

  1. 实例变量和局部变量的区别:实例变量声明在类中,局部变量声明在方法中,局部变量在使用前必须初始化,而实例变量在使用前如果没有被初始化会被自动赋值0/0.0/null
  2. equals 和 “==” 的区别:“==”是比较两个primitive主数据类型是否相等,或者两个引用变量是否引用到堆上的同一个对象。而“equals”是比较两个对象是否真的相等(类似于两个字符串相等一样的相等)
  3. Math.random()——会产生一个0~1之间的浮点数
  4. while和for循环的区别:已知循环次数的用for,不知循环次数的用while。while只有boolean测试,没有内建的初始化或重复表达式。
  5. 将String转换为int:int a = Integer.parseInt(“233333”);

将String转换为double:double b = Double.parseDouble(“233.33");

6.强制转换:(int)

6.建立一个对象: Dog myDog = new Dog();

7.ArrayList类:

ArrayList里面不能用primitive主数据类型,但是可以用他们的包装类

int -> Integer

double -> Double

float -> Float

short -> Short

bit -> Bit

long -> Long

char -> Char

String

ArrayList不可以用[ ]

8.在java的API中,类被包装在包中,要使用API中的类,就要知道它被放在哪个包中

import java.util.ArrayList;

除了java.lang之外,其他包的类都需要指定全名,或者程序开头用import指令来说明所使用到的包

9.包产生的三个原因:

用功能区分把一大堆零散的类用包组织起来,形成项目或者函数库

可以制造出名称空间,以便错开相同名称的类

包可以通过限制 同一包之间的类才能相互存取 以维护安全性

10.javax:以前曾经是没有包含在标准函数库内的扩展的类,后来被认可成为标准的一部分

11.java里面的import和c语言里面的include不同,运用import只是帮你省下每个类前面的包名称而已。程序不会因为使用了import而变大或者变慢

12.public class A extends B {

}

用“是一个”来检验是否成立继承关系——“三角形是个多边形”、“外科医生是一个医生”

而“有一个”只能表示类中拥有一个实例变量

A继承自B,表示A可以做B中的任何事情

13.子类打算引用父类的方法然后还打算加上额外的行为:

14.四种存取权限(access level):

private 、 default 、 protected 、 public

15.子类会继承父类中所有public类型的实例变量和方法,继承下来的方法可以被覆盖掉,但是继承下来的实例变量不能被覆盖

16.运用多态时,引用类型可以是实际对象类型的父类

参数和返回类型也可以多态,参数可以是A,而传入的参数可以是A的子类

所以说通过多态,可以编写出引进新型子类时也不必修改的程序

17.有三种方法可以防止某个类被继承出子类:

1.存取限制。虽然类不能标记为私有,但是可以不标记公有。非公有的类只能被同一个包的类继承出子类

2.使用final修饰符。表示这是继承树的末端,不能被继承。

3.让类只拥有private的构造程序

18.想要防止特定的方法被覆盖,也可以使用final修饰符,让这个方法不能被继承

19.覆盖(override):当要覆盖父类的方法时,参数必须一样,返回类型必须要兼容(必须返回一样的类型或者该类型的子类),不能降低方法的存取权限(也就是说存取权必须相同,或者更为开放),否则是不能覆盖成功的(也叫重写==override)

20.重载(overload):重载就是两个方法的名称相同,但是参数不同。所以重载和继承、多态没有任何关系。重载的参数必须不同,(在此基础上,返回类型可以自由定义,存取权限也可以自由定义),但是决不能只改变返回类型而不改变参数

21.abstract(抽象):当设计好继承结构时候,就应该决定哪些类是抽象的,哪些类是具体的。具体的类是实际可以被初始化为对象的。编译器不会让你初始化抽象类:Animal is abstract;can not be instantiated.

除了抽象类之外,也可以把方法标记为abstract的。如果你声明出一个抽象的方法,那么必须将类也标记为抽象的。不能在非抽象类里面定义抽象的方法。(就算只有一个抽象的方法,此类也必须标记为抽象的)

抽象的方法没有方法体,声明完成后直接以分号结束:

22.抽象方法的意义是:就算无法实现出方法的内容,但还是可以定义出一组子型共同的协议。

抽象的方法没有具体内容,只是为了标记出多态而存在。在继承树结构下的第一个具体类必须实现出所有的抽象方法(除法你在继承树结构下标记为抽象类,然后通过抽象机制将实现的负担转给下一层)

23.在java中所有的类都继承自Object类,这个类是所有类的源头。

Object类不是抽象类,它是具体的

24.hashCode() —— 列出一个对象的哈希代码

getClass() —— 得到一个对象是从哪里被初始化的

25.把所有东西都以多态来当做是Object会让对象看起来失去了真正的性质

当一个Dog类型的对象被声明为Object类型的对象被引用的时候,它无法再赋值给Dog类型的变量,只能赋值给Object类型的变量

编译器只根据引用的类型来判断有哪些方法可以用,而不是根据Object确实有的类型,就算你知道对象有这个功能,但是编译器只管引用的类型,不管对象的类型

Object的引用只能控制Object的功能

26.Object引用变量在没有类型转换的情况下不能赋值给其他类型。可以通过强制转换将Object类型转换为Dog类型,为了能够调用Dog所拥有的方法:

27.JAVA不允许继承多个父类,因为如果两个父类不同地实现了同一个方法,那么会导致子类不知道继承哪一个方法。解决的方法就是使用接口(interface)。以interface来取代class这个词来声明接口。

java的接口就好像是100%的纯抽象类。所有接口的方法都是抽象的,必须得实现

定义:public interface Pet {…}

实现:public class Dog extends Canine implements Pet {…}

28.接口的方法一定是公开抽象的(public abstract),这两个修饰词可写可不写。接口是多项的,所以里面的方法都是没有内容的。接口是多继承的,一个类可以extends一个父类,然后再implements 好多个接口(类可以实现多个接口)。

实现某接口的类必须实现它所有的方法。

29.接口的好处:不同的继承树上的类可以实现同一个接口,但是如果是用类来实现多态的话,必须是同一个继承树上,而且必须是这个类的子类(类来自单亲家庭(superclass),但可以扮演多重角色(implement))

30.只有在需要某类的特殊化版本的时候,以覆盖或增加新的方法来继承现有的类

当你需要定义一群子类的模板,但又不想让程序初始化此模板的时候,设计出抽象的类给它们使用

如果想要定义出类可以扮演的角色,用接口

31.可以在子类中使用super.func();调用父类的方法

32.抽象的方法没有内容,它的声明是以分号结束;抽象的方法必须在具体的类中运行

33.对象的生存空间——堆(heap)

方法调用及局部变量的生存空间——栈(stack)

实例变量存在于所属的对象中(所以实例变量在堆heap上),它被声明在类里面而不是方法里面

局部变量和方法的参数都是声明在方法中,它们是暂时的,生命周期只限于方法放在栈上的这段时间(所以也叫栈变量)

34.当你调用一个方法时,这个方法就会被放在调用栈的栈顶(其实放上去的是堆栈块,里面有方法的状态、执行到哪一行、所有的局部变量的值)

35.对象本身只会存在于堆上,局部变量对该变量只是引用,只有变量本身会放在栈上

36.JAVA会在堆上为对象分配一定空间(包括它的实例变量的空间),如果实例变量是对象类型,那么给它分配空间的大小是引用量的大小而不是对象本身的大小

37.Dog myDog = new Dog();   其中Dog()是在调用Dog类的构造函数,这个构造函数在你初始化一个对象的时候执行,唯一能够调用构造函数的办法就是新建一个类。

方法有返回类型,而构造函数没有返回类型。构造函数不会被继承。

如果需要有程序代码帮忙初始化,例如需要通过用户的输入来完成对对象的创建,那就需要自己写构造函数了。

38.函数(function)和方法(method)的区别:函数是大家的函数,方法是类的方法。C中只有函数,java中只有方法,C++取决于它是否在类里面。

39.如果某种对象不应该在状态初始化之前就使用,可以把初始化的程序代码放在构造函数中,然后把构造函数设定成需要参数的

40.

41.如果你完全没有写构造函数,那么编译器会自己帮你写;但是如果你已经写了一个有参数的构造函数,如果你需要一个无参数的构造函数,那么你必须自己写,编译器不会帮你写。编译器只会在你没有写构造函数的时候调用编译器写的默认构造函数。

42.编译器判断参数是否不同,判断的是类型和顺序,而不是名称。如果你写的两个函数一个只含int a, 一个只含int b, 那么是无法通过编译的。double int 和int double 却可以通过编译因为参数的顺序不同。

43.构造函数必须与类同名并且没有返回类型。默认的构造函数是没有参数的,你可以自己写个有参数的构造函数,一旦你写了新的构造函数,编译器默认的构造函数就不存在了,如果你还需要一个无参数的构造函数,则必须自己写一个。

重载的构造函数意思是有超过一个以上的构造函数

44.实例变量有默认值。0、0.0、false、null。写在方法里面的变量叫做局部变量,没有默认值。

45.调用父类函数的唯一方法是调用super();创建子类的同时也会调用父类构造函数,如果没有调用,编译器会自动加上super()的调用。

46.为了避免构造函数要写很多重复的代码(比如只有参数不同,其他代码部分都是相同的),可以使用this。使用this()可以从某个构造函数中调用同一个类的另一个构造函数。

this()只能用在构造函数中,且必须是第一行语句。

super()和this()不能兼得。

在其他函数中只能用”this.”来访问当前类的成员变量。

47.局部变量只会存活在声明该变量的方法中

实例变量的寿命与对象相同

48.life与scope的区别:一个是存活时间,一个是作用范围。局部变量还活着的时候,它的状态会被保存。但是该局部变量只能在拥有它的方法待在栈顶的时候才能使用。也就是说局部变量只能在声明它的方法在执行中才能被使用

49.除非有对该对象的引用,否则这个对象是无意义的。如果对对象的唯一引用消失了,对象就会被垃圾收集器回收。

有三种方法可以释放引用:

1;引用在某方法中,而方法调用结束后引用消失。

2;引用被赋值到其他对象上

3;直接将引用置为null

50.非静态方法与静态方法的区别:

例如Math这个类是不可以new的,因为它的构造函数是私有的。实际上它也无需创建Math对象,因为Math类里面所有的方法都是静态方法,都可以直接通过类名来调用它里面的方法。

所以以类的名称调用静态方法,以引用变量的名称调用非静态的方法

51.静态的方法是在无关特定的类的实例情况下执行的。静态的方法是直接通过类的名称来调用,所以静态的方法无法引用到该类的任何实例变量。

静态变量:静态变量的值对所有的实例来说都相同,静态变量只会在第一次载入的时候被初始化,之后就不会被初始化了:public static int a = 0

对于类里面的静态变量,这个类的所有实例拥有的静态变量只有一份,所以对于任何实例变量来说这个静态变量的值都是相同的,而不像类里面的其他实例变量一样,每个不一样的对象里面都有一份单独的实例变量的值

所以说静态变量是共享的。同一个类的所有实例共享这一份静态变量。而实例变量是每个对象都有一个。

52.静态变量是在类被加载时初始化的。静态变量会在该类的任何对象创建之前就被初始化。静态变量会在该类的任何静态方法执行前就被初始化。

静态变量也是通过类的名称直接存取。

静态变量的默认值是该变量类型的默认值,就和实例变量被赋予默认值一样。

53.标记为final的变量表示它一旦被初始化,它的值就不会被改变。这样就可以识别这个变量是个常数。常数变量的名称应该都是大写字母。

public static final double PI = 3.141592653589793

54.静态final变量初始化的两种方式:

1;声明的时候

2;在静态初始化程序中

如果没有按照上述两种方式中的一种初始化,那么编译器会报错

55.final不仅仅可以用在静态变量上,其他类型的变量上也可以使用,用来标记它的值不能够再被改变。

final int size = 3;

final double a = 3.22;

final 不仅仅可以用在变量上,还可以用在类和方法中。

final用在在方法中表示这个方法不能再被覆盖掉,在类中表示该类不能被继承,也就是你不能写出一个类是它的子类。

如果类已经是final,再标记类里面的方法是final就是多余的了。

56.静态方法可以存取静态变量,不可以存取非静态变量

57.Math类的常用方法:

58.primitive主数据类型的包装:java 5.0之前要手动包装,java 5.0之后可以编译器自动包装

Character

Integer // 只有char-Character、int-Integer拼写不同,其他都是直接primitive主数据类型变换第一个字母大写而来的。

Boolean

Long

Byte

Double

Float

Short

59.有了autoboxing之后,不必把primitive主数据类型和对象分得那么清楚

如果方法的参数或者返回值是主数据类型,你可以传入/返回对象,反之亦然

条件表达式的boolean,你可以传入对象或者主数据类型,都可以兼容

数值运算与赋值也是,对于对象或者primitive主数据类型都可以

60.将String转换为primitive主数据类型也非常容易:

int a = Integer.parseint(“123”)

double b = Double.parsedouble(“123.456”)

如果string不符合这样的转换类型,那么会抛异常

61.反过来primitive主数据类型也可以变为String:

double b = 42.5;

String s1 = “” + b;

String s2 = Double.toString(b);

62.数字的格式化:

将数字以带逗号的形式格式化:String s = String.format(“%,d”, 100000000);

其他和c语言printf相同,但是要用format的方法调用

日期的格式化:

new Date() 表示现在的时间

%tc完整的日期和时间

%tr只有时间

%tA %tB %td 周 月 日

<符号可以表示重复利用前一个参数,可以避免参数要写很多次相同的

Date today = new Date();

String.format(“%tA %<tB %<td”, today);

63.使用Calendar类来操作日期:

64.使用import static 可以少打几个字:当然如果少量使用的话,建议不这么写,否则程序会变得不易阅读。更重要的问题是,可能会很容易产生名称的冲突。比如add()到底是要调用哪个方法?会产生冲突。

异常处理

65.JavaSound API包括两部分,MIDI和取样(sampled)。MIDI表示Musical Instrument Digital Interface,是不同电子发声装置沟通的标准协议。

66.使用try/catch块来处理风险异常:

67.异常是一种Exception类型的对象

你写在catch块中的程序必定和抛出的异常有关。例如,如果遇到服务器出故障的异常,你可能会在这里写寻找替代服务器的方法。

throw用来抛出异常,try catch用来处理异常。

  • 有风险、会抛出异常的(throw部分)代码:

  • 调用该方法的程序代码:

68.不是由编译器检查的RuntimeException的子类,被称为检查异常,RuntimeException被称为不检查异常。除了RuntimeException这种特例之外,编译器会关照Exception所有的子类。

try/catch用来处理真正的异常,而不是你程序的逻辑错误。该块要做的是恢复的尝试,或者至少会优雅的列出错误信息。

69.方法在可运行期间遇到问题时抛出异常。

异常是Exception类型的对象。

编译器不会注意RuntimeException类型的异常。RuntimeException不需要声明或包在try/catch的块中。

编译器所关心的是称为检查异常的异常。程序必须要认识有异常可能的存在。

方法可以用throw关键词抛出异常对象:throw new FileIsTooSmallException();

可能会抛出异常的方法必须声明成throws Exception。

如果不打算处理异常,还是可以正式地将异常给ducking来通过编译。

在try/catch语句块中,如果try部分代码执行到一半发现了异常,会直接跳转到执行异常的地方去,try中其余没有执行的代码不会再被执行。因为那些都是要依赖之前的成功才能执行下去的代码。

70.为了防止不管成功还是失败你最后都要执行的代码要写在try和catch里面两遍,所以发明了finally。

如果try或者catch块有return指令,finally还是会执行!流程会跳到finally然后再回到return指令

71.可以抛出一个以上的异常,处理多重异常

72.Exception是所有异常的父类,我们可以以异常的父型来声明会抛出的异常,也可以用抛出的异常父型来catch异常,这样就包括了这个当前异常的所有子类

73.但是最好try catch的时候分别catch不同的异常,不要把它们用一个父类表示混在一起,因为你会不知道到底是哪个异常出了问题,所以会导致不知道具体怎么解决。如果很多个异常,其中几个是不同的处理方法,剩余的是一样的处理方法,你可以使用catch(Exception1) catch(Exception2)然后最后catch(fatherException)的方式用fatherException处理其他所有的子类异常。

不要把父类异常的catch放在子类的上面,这样子类的异常处理会执行不到的~~但是如果两个异常是平级的,那么就无关顺序了,因为两者都不会吞下对方的异常~

74.如果你不想处理异常,你可以把它duck掉来避开。就是说声明了异常,但是并没有try/catch块来处理有风险的这个方法,这样会让异常不断抛给调用自己当前方法的另一个方法,直到有一个方法处理了异常情况。但是如果发现到最后main也忽视掉了这个异常,那么虚拟机就会go die。。

75.异常处理规则:

  • catch和finally不能没有try。
  • try和catch之间不能有程序代码。
  • try一定要有catch和finally
  • 只带有finally的try必须要声明异常,如:throws MyException
图形用户接口

JFrame是个代表屏幕上window的对象。你可以把button、checkbox、text字段等接口放在window上面。标准的menu也可以加到上面,并且能够带最小化、最大化、关闭等图标。

一旦创建出JFrame后,你就可以把组件(widget)加到上面。有很多Swing组件可以用,它们是在javax.swing这个包中。最常用的组件包括:

  • JButton
  • JRadioButton
  • JCheckBox
  • JLabel
  • JList
  • JScrollPane
  • JSlider
  • JTextArea
  • JTextField
  • JTable

创建GUI的步骤:

1.创建frame

2.创建widget

3.把widget加到frame上

4.显示出来

76.按钮的外观有两种可以选,Metal为java的标准界面,不指定的话就会显示平台默认的外观。Windows上显示Windows风格按钮,Mac上显示Aqua外观

77.以前Swing很慢,现在不是了。很多应用程序都用Swing。

78.在Java上,取得与处理用户操作时间的过程称为even-handing

按钮等控件叫做事件源,事件源会在用户做出相关动作时(按下按钮)产生事件对象。程序是事件的接收方。每个事件烈焰都有相应的监听接口。想要接收MouseEvent的话就实现MouseListener这个接口,如果要实现接口,就要声明这件事,并且把接口中所有的方法都实现出来~

79.某些接口不只有一个方法,因为事件本身就有不同的形态。比如MouseListener,事件就有mousePressed、mouseReleased、mouseMoved。这些都是MouseEvent,所以虽然鼠标事件只有MouseEvent一种事件对象,却有不同的事件方法来表示不同类型的鼠标事件。

事件源负责发出事件,事件Event对象携带事件信息,监听获知事件。

80.在GUI上面加东西的3种方法:

  • 在frame上放置widget

  • 在widget上绘制2D图形

  • 在widget上绘制JPEG图

81.在paintComponet()中可以做的事情

  • 显示JPEG

  • 在黑色背景画上随机色彩的圆圈

82.Graphics g : 由g参数所引用的对象实际上是个Grahpics2D实例。如果要调用Graphics2D类的方法,就不能直接使用g参数,需要转换成Graphics2D变量:

83.frame默认有5个区域可以安置widget。每个区域只能安置一项——north,west,east,south,center

84.一个类可以嵌套在另一个类的内部。内部类可以使用外部所有的方法与变量,就算是私用的也一样。这就是为何内部的类这么好用的原因,因为除了跟正常的类没有差别之外,还多了特殊的存储权。

内部类的实例一定会绑在外部类的实例上,不可能去存取其他外部类的方法和变量,只能存取他所属的那个对象

运用Swing

从技术上来说,widget是一个Swing的组件,几乎所有的组件都继承自javax.swing.JComponent,组件是可以嵌套的。

三种布局管理器:

  • BorderLayout

这个管理器会把背景组件分割成5个区域。每个被管理的区域只能放上一个组件。这是框架默认的布局管理器

  • FlowLayout

这个管理器的行为和文本处理程序的版面差不多,从左到右排列,按照理想的大小呈现,有必要的时候会换行。组件放不下的时候就会被放到下一行,这是面板默认的布局管理器

  • BoxLayout

这个管理器让每个组件垂直方向排列,从上到下每行一个,强制自动换行。

序列化和文件的输入/输出

储存状态的两种方法:

  • 将被序列化的对象写到文件中。序列化的文件是很难让一般人阅读的,但它比纯文本文件更容易让程序恢复状态。也比较安全。因为一般人不会知道如何动手脚改数据。
  • 谢承恩纯文本文件,用特殊字符分隔。

85.将序列化对象写入文件的步骤:

  • 创建出FileOutputStream

  • 创建ObjectOutputStream

  • 写入对象

关闭ObjectOutputStream

86.当对象被序列化时,被该对象引用的实例变量也会被序列化。且所有被引用的对象也会被序列化。序列化程序会将对象版图上的所有东西存储起来。

整个对象版图都必须正确地序列化,不然就得全部失败。序列化是全有或者全无的。如果某实例变量不能或不应该被序列化,就把它标记为transient(瞬时)的

这样序列化程序会把它跳过。

87.解序列化(Deserialization):还原对象的步骤:

  • 创建FileInputStream

  • 创建ObjectInputStream

  • 读取对象

输入输出

流:一维单方向的

System.out.println——out也是一个流

java中所有的输入和输出都是基于InputStream、OutputStream两个流的

国标码汉字的长度为每个字2个字节,1个字符(unicode)

  • InputStream
    • read()
    • int read()
    • read(byte b[])
    • skip(long n)
    • int available()
    • mark()
    • reset()
    • boolean markSupported()
    • close()
  • 文件流:FileInputStream、FileOutputStream,对文件作读写操作。实际工程中已经很少使用,更长用的是以在内存数据或通信数据上建立的流,如数据库的二进制数据读写或者网络端口通信。具体的文件读写往往有更专业的类,比如配置文件和日志文件

未完待续

网络与线程
数据结构
  • TreeSet——以有序状态保持并可防止重复,如果你把字符串放入,这些字符串会自动的按照字母顺序排列。
  • HashMap——可用成对的name/value来保存与取出
  • LinkedList——针对经常插入或者删除中间元素所设计的高效率集合
  • HashSet——防止重复的集合,可以快速地找寻相符的元素
  • LinkedHashMap——类似HashMap,你可以记住元素插入的顺序,也可以设定成按照元素上次存取的先后来排序

88.使用Collections.sort()对ArrayList排序:

89.泛型:List<T>

运用泛型你就可以创建类型安全更好的集合,让问题尽可能在编译器就能抓到,而不会等到执行期才冒出来。几乎只有集合才会真正需要泛型,一般都是API设计泛型,自己用来使用就行。

发布程序

JAR文件——JavaARchive,是一个pkzip格式的文件。它能让你把一组类文件包装起来,所以交付时只需要一个JAR文件。可以直接双击JAR就开始执行。

我们可以使用包来防止类名称的冲突。但这只会在包名称保证不重复的情况下起作用。所以最好的方式是在前面加上domain名称~(反向使用)com.oreilly.projects.Chart

远程部署的RMI