1. 下载JDK(Java Development Kit,Java开发包)

2. JRE(Java Runtime Environment,Java运行时环境)

3. JDK包含了JRE。

4. 关于Java的版本:

JDK 1.4

JDK 1.5 == JDK 5.0, tiger (老虎)

JDK 1.6 == JDK 6.0, mustang(野马)

5.我们的课程讲的是JDK 1.6。

6.配置环境变量。

要配置两个环境变量

1) path:指定到jdk安装目录的bin目录下

2) classpath:值为.,表示当前目录

7.如何查看环境变量:在命令行输入set path命令。

8.编写Java程序要使用纯文本编辑器,比如notepad,editplus,ultraedit。

9. Java源文件的后缀名必须是java。

10.Java程序的开发步骤

1) 编写Java源代码(source code),存储到后缀名为java的文件中(源文件,source file)。

2) 使用javac命令编译java源文件:javac HelloWorld.java。编译之后会生成一个后缀名为class的文件(字节码文件,bytecode)。然后通过执行字节码文件实现跨平台的运行。(Write once, Run anywhere,编写一次,到处运行)

3)执行。执行使用的命令是java,方式是:java HelloWorld(注意,不要包含.class后缀名)

11. 如果使用了public,那么源文件名需要与类名保持一致;如果没有使用public,那么源文件名与类名可以不一致。

12.注释。Java中的注释分为三种。

1)单行注释 //这是注释,Java编译器会将//后面的所有内容全部忽略掉,注释是给开发者看的,不是给Java编译器看的。

2)多行注释。/*与*/之间的所有内容都会被Java编译器忽略掉。多行注释不能嵌套。

3) 另一种多行注释

/**

*/

13. 变量与常量。变量就是可以变化的量,常量是不可以变化的量。比如数字5就是一个常量,因为它无法再改变了。

变量:要想使用变量,必须先定义变量。如何定义变量?

类型 变量名; //变量的定义

变量名=具体值; //变量的赋值

将上面两步操作合并为一步:

类型 变量名 = 具体值;

int a = 100; //表示定义了一个整形变量a,并且将100赋给a

类型:Java中一共有两大部分类型:第一种叫做原生数据类型;第二种叫做引用类型(对象类型)。

14 原生数据类型(基本数据类型)。Java中一共有8种原生数据类型。

1) 整型:用int表示。

2) 字节:用byte表示。

3) 短整型:用short表示。

4) 长整型:用long表示。

5) 字符类型:用char表示。仅表示一个字符,比如字母a,汉字张等,用单引号包围。

6) 单精度浮点型:用float表示。

7) 双精度浮点型:用double表示。所谓浮点型,其实就是小数,或者叫做实数。

8) 布尔类型:用boolean表示,该类型一共只有两个值:true与false。true表示真,false表示假。

15.强制类型转换,将表示范围大的值转换为表示范围小的类型的值。

float a = (float)1.2;

浮点数的默认类型是double,1.2是double类型,它无法直接赋值给表达范围更小的float类型,必须要经过强制类型转换,强制类型转换的语法是:

类型 变量名 = (类型)变量值;

16. Java中的变量在使用前必须要定义,而且只能定义一次。如下代码是错误的

int a = 100;

int a = 200;

因为变量a定义了两次,造成重复定义。

如下代码也是错误的

a = 100;

System.out.println(a);

因为变量a没有定义。

如何同时定义多个变量?

变量类型 变量名1, 变量名2,…….,变量名n;如:

int a, b, c;

要想使用变量,首先需要定义,然后必须赋值。

如下代码是错误的,因为变量a并没有赋值。

int a;

System.out.println(a);

 

17. 关于变量名的命名约定,以字母,下划线,或者$开头,后接字母、下划线、$以及数字,没有长度限制。

18. 关于强制类型转换的注意事项:当把表示范围小的类型赋给表示范围大的类型,可以直接赋值,无需强制类型转换;但当把表示范围大的类型转换为表示范围小的类型,则必须要进行强制类型转换。

19.int a = 8;

int b = a / 3;

如果无法整除,那么将小数点后的部分全部舍去,只保留整数部分

 

20. int a = 1;

int b = a++;

表示先将a的值赋给b,然后a再加一,结果是a为2,b为1。

int a = 1;

int b = ++a;

表示先将a的值加一,然后讲加完的结果赋给b,结果是a为2,b为2

--的道理与++类似

                      第二节

 

1

double a = 3.5;

int b = 2;

 

double c = a / b;

 

对于上面的程序,a是double类型,b是int类型,这样当a与b相除时,结果类型取决于a与b中表示范围最大的类型,由于double类型表示的数据范围要比int类型大,因此a与b相除的结果类型就是double,所以需要将变量c声明为double类型。

 

2. 运算优先级。与数学上的运算是一样的,都是先乘除,后加减;可以使用小括号改变运算数的优先级。如下程序:

int a  = 3, b = 8, c = 9;

 

int d = (a - b) / c;

会先计算a – b,然后用结果除以c。

 

3. 关系运算符。关系运算的结果是个boolean类型的值。

 

4. 布尔逻辑运算符。操作数必须是布尔类型的数据。

1)逻辑与:&&,操作数是两个,只有两个操作数都为true,结果才为true,否则结果为false。

2)逻辑或:||,操作数是两个,如果两个操作数中有一个为真,结果就为真,否则结果为假。

 

5. 关于布尔运算符的短路特性。

1)逻辑与&&:如果第一个操作数为假,则不再进行第二个操作数的判断(因为结果已经确定为假);如果第一个操作数为真,则继续进行第二个操作数的判断。

2)逻辑或||:如果第一个操作数为真,则不再进行第二个操作数的判断(因为结果已经确定为真);如果第一个操作数为假,则继续进行第二个操作数的判断。

 

6. 条件运算符。条件运算符是个三元表达式。

 

type d = a ? b : c;

 

7. 控制结构。

 

  1. if语句

 

第一种方式

 

if(布尔表达式)

{

//程序代码

}

 

第二种方式

 

if(布尔表达式)

{

//程序代码

}

else

{

//程序代码

}

 

第三种方式

 

if(布尔表达式)

{

//程序代码

}

else if (布尔表达式)

{

//程序代码

}

else if (表达式)

{

//程序代码

}

else

{

//程序代码

}

 

2) while语句:while是一种循环结构

 

while(布尔表达式)

{

//程序代码

}

3) do…while语句:do…while语句也是一种循环结构

 

do

{

//程序代码

}

while(布尔表达式);

 

关于while与dowhile的比较与分析:

  1. while语句先判断布尔表达式,然后再执行程序代码; dowhile语句先执行程序代码,然后再判断布尔表达式。
  2. 如果布尔表达式第一次判断的结果为false,那么while语句中的代码一次也不执行;而dowhile语句中的代码会执行一次。
  3. 如果布尔表达式第一次判断的结果为true,那么while语句等价于dowhile语句。

4) switch…case:作用类似于if…else if…else if…else结构

 

switch(变量名)

{

case 常量1:

//程序代码

break;

case 常量2:

//程序代码

break;

case 常量3:

//程序代码

break;

default:

//程序代码

}

switch语句中的变量类型只能是byte, short, int以及char。

 

5) for语句:for语句也是一种循环结构,并且是使用最多的一种循环结构

 

for(变量初始化; 条件判断; 步进)

{

//程序代码

}

 

  1. 进行变量初始化。
  2. 执行条件判断:如果条件判断的结果为假,则退出for循环,不再执行循环体中的内容;如果条件判断为真,则执行循环体中的内容。
  3. 执行步进。
  4. 重复步骤2

 

8. 求模运算符:用%表示,表示求出两个整型相除的余数。

 

int a = 6 % 5

 

a的结果就是1

 

                                第三节

  1. break通常用在循环语句中,用于跳出循环语句,执行循环下面的语句。
  2. continue通常用在循环语句中,用于跳出本次循环, 开始下一次循环的执行。
  3. 面向对象的程序设计:Object-Oriented Programming (OOP)。
  4. 类(class):可以将类看做是数据(通常使用名词表示,叫做成员变量或属性)与操纵数据的方法(通常使用动词表示,方法叫做method)的结合体。
  5. 如何定义类?

 

修饰符 class 类的名字

{

//类的内容 (包含了属性与方法)

}

  1. 方法。如何定义方法?

 

修饰符 返回类型 方法名称([参数1, 参数2, 参数3……])

{

//方法体

}

  1. main方法是整个Java程序的入口点,如果类的定义中没有main方法,则程序将无法执行。
  2. 方法的定义不能嵌套,不能在一个方法中定义另外一个方法。方法只能定义在类中。
  3. 关于方法的执行:首先需要定义方法,接下来就可以使用方法(调用方法),当方法调用完毕之后,方法可以返回值。方法到底是否返回值是由方法的定义决定的
  4. 对象(Object),什么是对象?对象是类的一种实例化表示。对象与类的关系是非常紧密的。类是一种抽象的概念,对象是一种具体的概念;对于现实世界中:人(Person)就是一种抽象的概念;而具体的人(比如张三,李四,王五)则是具体的概念,对应于面向对象程序设计,人就可以看作是类,而张三这个具体的人就可以看作是对象。
  5. 如何生成对象?通过类来生成对象(通常使用new关键字来生成对象)。

public class Person

{

}

 

类名 变量名 = new 类名();

 

Person person = new Person();

Person person2 = new Person();

Person person3 = new Person();

 

12. 方法调用需要通过对象来完成。方法调用的形式为:

 

对象变量.方法名([参数值1, 参数值2, 参数值3..])

 

13. 关于方法的注意事项:

1)在方法定义中,方法的返回类型与return后面的变量或者常量的类型保持一致。

2)在方法调用时,给方法传递的参数需要与方法定义时的参数保持一致(参数个数一致,参数类型一致)

3)方法定义时的返回类型与接收方法返回值的变量类型保持一致。

 

14.

public int add(int a , int b)

{

int c = a + b;

 

return c;

}

方法定义时的参数叫做形式参数

 

int result = test.add(1, 2);

 

调用方法时所赋予的具体值叫做实际参数。

 

15. 关键字void表示方法不返回值。

16. 如果方法不返回值,那么声明的时候使用void关键字,在方法定义中可以有两种情况实现不返回值的方法

1)不使用return语句。

2)使用return,但return后面没有任何值或者变量,后面只有一个分号,表示退出方法,返回到方法的调用端  

使用方法: return;

 

                                      第四节

  1. 类中的属性又叫做成员变量(member variable),属性用英文表示为property或attribute。
  2. 对象(Object)又叫做实例(Instance)。生成一个对象的过程又叫做实例化。
  3. 命名约定
  4. 类:首字母大写,如果一个类名由多个单词构成,那么每个单词的首字母都大写,中间不使用任何的连接符。比如Person类,MemberTest类。
  5. 方法:首字母小写,如果一个方法由多个单词构成,那么第一个单词的所有字母全都小写,从第二个单词开始,每个单词的首字母大写。比如add, addThreeInt.
  6. 属性:与方法相同。比如age,ageOfPerson。
  7. 属性需要定义在类中,又叫做成员变量;而定义在方法中的变量叫做局部变量
  8. 局部变量使用前必须要声明并赋初值;成员变量使用前必须要声明,但可以不赋初值。
  9. 如何定义属性?

 

public class Person

{

修饰符 类型 属性名称;

}

如何使用属性?与方法一样,使用.运算符,首先需要生成类的实例,然后使用实例+.的方式来使用属性。

 

Person person = new Person();

person.age

  1. 成员变量与局部变量的联系与区别:
  2. 无论是成员变量还是局部变量,使用前都需要声明(定义)。
  3. 对于局部变量来说,使用前必须要初始化;对于成员变量来说,使用前可以不初始化。如果没有初始化成员变量就开始使用,那么每个类型的成员变量都有一个默认的初始值:
  1. byte,  short,  int, long类型的初始值为0
  2. float,double类型的初始值为0.0
  3. char类型的初始值为空的字符
  4. boolean类型的初始值为false

7. 引用类型:引用类型是用在对象上的。一个对象可以被多个引用指向,但同一时刻,每个引用只能指向唯一的一个对象。如果一个对象被多个引用所指向,那么无论哪个引用对对象的属性进行了修改,都会反映到其他的引用当中。

8. 如果一个类包含了属性与方法,那么该类的每一个对象都具有自己的属性,但无论一个类有多少个对象,这些对象共享同一个方法。

9. 关于方法参数传递的总结:对于Java中的方法参数传递,无论传递的是原生数据类型还是引用类型,统一是传值(pass by value)。

10. 什么类型的引用就能指向什么类型的对象,比如People类型的引用就能指向People类型的对象,但不能指向Student类型的对象。比如:

People  p = new People(); //正确

People p = new Student(); //错误

 

11. 构造方法(Constructor):构造方法用于完成对象属性的初始化工作,构造方法的特点:

1)构造方法的名字必须与类名完全一致(包含大小写)

2)构造方法没有返回值,连void也不能出现。

3)如果在定义一个类的时候,没有为类声明构造方法,那么Java编译器会自动为类添加一个没有参数且方法体为空的构造方法。

4)如果在定义一个类的时候,为类声明了构造方法,那么Java编译器就不会再为类添加构造方法了。

5) 不能显式调用构造方法,构造方法只能通过new关键字隐式调用。

 

12. new关键字完成了3件事情。

1)为对象开辟内存空间。

2)调用类的构造方法。

3)将生成的对象的地址返回。

 

13. 默认的构造方法:构造方法没有参数并且方法体为空。

14. 使用new来生成对象的时候,后面的小括号()表示构造方法的参数列表,如果构造方法不接收参数,那么小括号中的内容为空;如果构造方法接收参数,那么小括号中的实际参数就需要与构造方法定义中的形式参数保持一致(参数数量一致,参数类型一致,按照顺序逐一赋值)。

15. 方法重载(overload):对于两个或多个方法来说,方法的名字相同,但方法参数不同,这样的方法叫做重载方法。方法参数不同体现在两点:

1)参数个数不同。

2)参数类型不同。

 

方法是否重载完全由方法参数决定,方法的返回类型对方法是否构成重载没有任何影响。

 

16. 构造方法的重载:构造方法的重载与普通方法的重载要求是一样的,都是根据参数个数或参数类型的不同来判断两个或多个构造方法是否构成了重载关系。

17. this关键字:this是指向当前对象的引用。Java中的每个对象都拥有一个this引用,用于指向自身。

                     

                         第五节

  1. 类中的构造方法可以相互调用,方法是使用this()语句调用,该语句表示调用类中的其他构造方法,其中this后面的小括号表示参数列表。
  2. 如果构造方法中使用this()语句调用其他构造方法,那么this()语句必须是该构造方法的第一条语句,换句话说,this()语句前面不能有其他任何的执行语句。
  3. 面向对象的三大特性:继承、封装、多态。
  4. 如果一个java源文件定义了多个类,那么最多只能有一个类是public的,同时该java源文件的名字必须要与该public的类名相同;如果多个类都不是public的也是允许的,在这种情况下,java源文件的名字不必与任意一个类名相同。
  5. 在Java中,继承是通过extends关键字表示的。

 

class Dog extends Animal  //表示Dog继承了Animal

{

 

}

 

在继承当中,被继承的类叫做父类(基类),继承的类叫做子类。对于上面的代码示例,Animal叫做父类,Dog叫做子类。

  1. 关于继承需要理解如下3点:
  2. 父类有的,子类也有。
  3. 父类没有的,子类可以增加。
  4. 父类有的,子类可以改变。
  5. 属性与方法都是可以继承的,但构造方法不能继承。
  6. 当生成子类对象的时候,首先需要找到父类的不带参数的构造方法,然后执行该构造方法,生成父类的对象,接下来再去调用子类的构造方法,生成子类的对象。【要想生成子类的对象,首先需要生成父类的对象,没有父类对象就没有子类对象,比如:没有父亲,就没有孩子】
  7. 重写(又叫做覆写,英文是Override),指的是父类与子类的方法具有相同的返回类型、相同的方法名称、相同的参数列表,如果满足以上3个条件,那么这两个方法就构成了重写关系。
  8. 重载与重写的区别:重载发生在同一个类内部的两个方法;重写发生在父类与子类之间。
  9. super关键字:super表示对父类对象的引用。
  10. 如果子类使用super()显式指定调用父类的某个构造方法,那么在执行的时候就会寻找与super()指定所对应的构造方法而不会再去寻找父类的不带参数的构造方法了。与this一样,super也必须要作为构造方法的第一条语句。
  11. 如果仅仅使用super关键字调用父类的方法,那么super可以放在方法的任意位置上,而不必非得放在第一行语句处。
  12. 多态(Polymorphism),本质上就是父类型的引用可以指向子类的对象。
  13. Animal ani = new Cat(); 因为ani引用指向了Cat对象,因此ani调用的都是Cat类里面定义的方法与属性;但需要注意一点:ani是Animal类型的。
  14. Animal ani = new Cat(); ani.cry(); 当使用多态进行方法调用或属性设置时,首先检查父类中是否有cry()方法,如果没有则编译报错;如果有,则调用子类的cry()方法。
  15. 关于强制类型转换:一共有两种类型的强制类型转换
  16. 向上转换(upcast):比如说将Cat类型转换为Animal类型,即将子类型转换为父类型。对于向上转换,不需要显式指定。
  17. 向下转换(downcast):比如将Animal类型转换为Cat类型,即将父类型转换为子类型。对于向下转换,必须要显式指定。
  18. 包(package)用于将完成不同功能的类分门别类,放在不同的目录中。包的定义需要放在源代码的最上面,如package com.tsinghua;包名通常是公司网站域名的反转。包体现在硬盘上,就是一种嵌套的目录结构。编译带有package声明的java源文件有两种方式:
  19. 直接编译,然后根据类定义时所声明的包名,逐一建立目录结构,最后将生成的class文件放到该目录结构中。(很少使用,比较麻烦)
  20. 使用编译参数-d:方式为javac d . 源文件.java。这样在编译后,编译器会自动帮助我们建立好包所对应的目录结构。
  21. 有两个包名:分别是aa.bb.cc与aa.bb.cc.dd那么我们称后者为前者的子包。
  22. 导入(import):将使用package分离的各个类导入回来,让编译器能够找到所需要的类。import的语法:

import 包.类名; 比如: import com.tsinghua.Person;

import com.tsinghua.Man;

21.  aa.bb.cc是aa.bb的子包

 

import aa.bb.*;并不会导入aa.bb.cc下的类。

 

import aa.bb.*;

import aa.bb.cc.*;

 

22. 如果没有为一个类指定package,那么这个类所在的包就叫做默认包。

23. 关于package、import、class的顺序问题。

1)首先需要定义package(可选)

2)接下来使用import进行导入(可选)

3)然后才是类的定义

 

                         第六节

  1. 数组(Array):相同类型数据的集合叫做数组。
  2. 如何定义数组?

 

type[] 变量名 = new type[数组中元素的个数];比如说可以按照下列方式定义一个长度为10的整型数组:

 

int[] a = new int[10];

 

或者:

 

type 变量名[] = new type[数组中元素的个数];

 

type[] 变量名= {逗号分隔的初始化值列表}; 初始化列表中有多少个值,数组的长度就为多少,同时初始化列表会按照顺序将值赋给数组的每一个元素。

 

  1. 数组中元素的索引是从0开始的。对于数组来说,最大的索引 == 数组的长度  1。
  2. Java中的每个数组都有一个名为length的属性,表示数组的长度。数组长度一旦确定,就不能改变大小。
  3. 当生成一个数组对象后,数组中的每个元素都有一个初始值,每种元素类型的初始值与类的属性的初始值是一样的,比如int类型的 初始值为0,boolean类型的初始值为false等。
  4. int[] a = new int[10];,其中a是一个引用,它指向了生成的数组对象的首地址,数组中的每个元素都是int类型,其中仅存放数据值。
  5. Person[] p = new Person[10]; 其中p是一个引用,它指向了生成的数组对象的首地址,数组中的每个元素都是Person类型的引用,每个引用指向了一个Person类型的对象。
  6. 所谓二维数组,其实指的就是数组的数组,它是一种平面的二维结构,定义方式为:

Int[][] a = new int[2][3]; 其中的2表示数组的行数,3表示数组的列数。换句话说,2表示数组的第一维,3表示数组的第二维。

  1. 如果一个数组为引用类型的数组,那么数组中的每个引用的默认值都为null。null是所有的引用类型d的默认值。
  2. IDE(Integrated Development Environment,集成开发环境)。目前Java领域比较优秀的IDE有如下几个:
  3. Eclipse(日蚀,月蚀)。目前的最高版本是3.6。免费,开源(Open Source)。官方网站是: http://www.eclipse.org。本身不用安装。
  4. NetBeans,是由Sun公司开发的一款强大的Java IDE。目前的最高版本是6.9。免费。http://www.netbeans.org
  5. Intelij IDEA,是一款商业IDE,收费的。
  6. 使用Eclipse进行开发时,需要首先建立一个工程,然后在工程中建立包与文件。
  7. static关键字是个修饰符,可以用来修饰方法与属性,如果某个方法被static所修饰,那么我们称该方法为静态方法,这时我们就可以使用类名.静态方法名的方式来调用该静态方法以执行;也可以按照以前的方式,先生成类的对象,然后通过引用.静态方法名的方式来调用该静态方法以执行。但推荐使用前者(类名.静态方法名的方式)。
  8. 当static修饰属性时,该属性叫做静态属性。这时,无论类生成了多少个对象,所有这些对象共享同一个静态属性。也就是说,通过一个对象的引用修改了静态属性值,那么这种修改也会反映到其他对象的引用上,因为静态属性在内存中只有一份;如果属性不是static的,那么有多少个对象就会有多少个属性,这些属性之间是互不干扰的。
  9. 当属性被static所修饰时,既可以通过引用.属性名的方式来调用,也可以通过类名.属性名的方式来调用,推荐使用后者(类名.属性名的方式),这一点与静态方法类似。
  10. 静态代码块。

static

{

System.out.println("静态代码块");

}

 

静态代码块的作用也是完成一些初始化工作。先执行静态代码块,再去执行构造方法。静态代码块在类被加载的时候执行,而构造方法在生成对象的时候执行;要想调用某个类来生成对象,首先需要将类加载到JVM(Java Virtual Machine)上,然后由JVM加载的这个类来生成对象。

类的静态代码块只会执行一次,是在类被加载的时候执行的,因为每个类只会被加载一次,所以静态代码块只会执行一次;而构造方法则不然,每次生成一个类的对象时都会调用一次构造方法。所以new一次就会调用构造方法一次。

 

如果继承体系中既有构造方法,又有静态代码块,那么首先执行最顶层的类的静态代码块,一直执行到最底层的静态代码块,然后再去执行最顶层的构造方法,一直执行到最底层的构造方法,这里需要注意的是:静态代码块只执行一次

 

  1. 不能在静态方法中访问非静态成员变量。可以在静态方法中访问静态的成员变量。可以在非静态的方法中访问静态的成员变量。

总结:静态的只能访问静态的,非静态的可以访问一切。

 

  1. 不能在静态方法中使用this关键字。
  2. final关键字。final关键字是一个修饰符,可以修饰类、方法以及属性。
  3. final修饰类的时候表示该类是不能被继承的,不能被继承的类叫做终态类。
  4. final修饰方法的时候表示该方法不能被子类重写(override)。
  5. final修饰属性的时候表示该属性不能被重新赋值。

 

API: Application Programming Interface(应用编程接口)

 

 

作业:随机生成50个整数,每个整数介于1到20之间,也就是说每个整数要大于等于1并且小于等于20,  1 <= m <= 20,统计每个整数出现的次数,然后找出出现次数最多的那个整数并且将该整数及其出现次数在控制台上输出;输出这50个整数每个整数出现的次数并且按照次数的升序输出。

 

 

                                     第七节

 

  1. 抽象类。使用了abstract所修饰的类就叫做抽象类。抽象类无法实例化,也就是说,不能new出来一个抽象类的对象(实例)。
  2. 抽象方法。使用abstract所修饰的方法叫做抽象方法(有声明,无实现),抽象方法只有声明,没有实现。抽象方法需要定义在抽象类中。相对于抽象方法来说,以前所定义的方法叫做具体方法(有声明、有实现)。
  3. 如果某个类包含了抽象方法,那么该类一定是抽象类。
  4. 如果某个类是抽象类,那么该类可以包含具体方法。
  5. 如果一个类中包含了抽象方法,那么该类一定要声明为abstract class,也就是说,该类一定是个抽象类;反之,如果某个类是抽象类,那么该类既可以包含抽象方法,也可以包含具体方法。
  6. 无论何种情况,只要一个类是抽象类,那么这个类就无法实例化。
  7. 在子类继承父类(父类是个抽象类)的情况下,那么该子类必须要实现父类定义的所有抽象方法;否则,该子类就需要声明为一个abstract类。
  8. 接口(interface)。接口的地位等同于class,接口中的所有方法全都是抽象方法,在声明接口中的方法时,可以使用abstract关键字,也可以不使用。通常情况下,都不使用abstract关键字。
  9. 如何定义接口,使用关键字interface。接口无法实例化。
  10. 类可以实现接口。实现使用关键字implements表示,代表某个类实现了某个接口。
  11. 一个类实现了某个接口,那么该类必须要实现接口中所声明的所有方法。如果该类是个抽象类,那么就无需实现接口中的方法了。
  12. Java是单继承的,也就是说某个类只能有唯一一个父类;一个类可以同时实现多个接口,多个接口之间使用逗号分隔。

 

public class MyClass implements InterfaceA, InterfaceB

{

//类体

}

 

public class MyClass extends ParentClass implements ParentInterface

{

//类体

}

 

 

  1. 接口中除了抽象方法以外,还可以定义成员变量。接口中的成员变量一定是final,static,public的。
  2. 多态:所谓多态,就是父类型的引用可以指向子类型的对象,或者接口类型的引用可以指向实现该接口的类的实例。关于接口与实现该接口的类之间的强制类型转换方式与父类和子类之间的强制类型转换完全一样。
  3. 一个类可否既是final的,又是abstract的?不可以,因为abstract的主要目的是定义一种约定,让子类实现这个约定,而final表示该类不能被继承,这样abstract希望该类可被继承而final明确说明该类不能被继承,两者矛盾,因此一个类不能既是final的,又是abstract的。
  4. 访问修饰符:
  5. public(公共的):被public所修饰的属性和方法可以被所有类访问。
  6. protected(受保护的):被protected所修饰的属性和方法可以在类内部、相同包以及该类的子类所访问。
  7. private(似有的):被private所修饰的属性和方法只能在该类内部所使用。
  8. 默认的(不加任何访问修饰符):在类内部以及相同包下面的类所使用。

 

  1. 字符串(String):String是常量,其值一旦确定就不能被改变。对于String的拼接来说,永远是产生新的对象而不是改变原有对象的内容。
  2. java.lang包下的所有类在使用的时候无需显式导入(import),Java编译器在编译的时候会自动帮助我们将该包下的类与接口导入进来,除了java.lang包以外,其他包下面的类在使用的时候必须要显式导入进来。
  3. 相等性的比较。

1)==对于原生数据类型来说,比较左右两边的值。

2)==对于引用类型来说,比较左右两边的引用是否指向同一个对象,或者说左右两边的引用的地址是否相同。

  1. java.lang.Object是Java所有的类的父类,换句话说,Object是继承体系的根。在定义一个类的时候,如果该类没有继承其他的类,那么该类实际上就是继承了Object类。
  2. 关于字符串的比较。对于字符串的比较来说,不要使用==来比较,使用equals方法。equals方法定义在Object类中,在Object中,equals方法比较的依然是引用的地址是否一致,换句话说,比较两个引用是否指向了同一个对象,也就是说,Object类中的equals方法等价于==。
  3. 因为Java中所有的类都直接或间接地继承自Object类,所以每个类都有equals方法。但通常,每个类都会重写equals方法,使得equals方法的意义变为判断两个对象的内容是否一致。
  4. 当使用System.out.println()打印出一个引用时,实际上Java会调用该引用所指向对象的toString()方法,因此以下两种表达方式是等价的:

Object obj = new Object();

System.out.println(obj);  <->  System.out.println(obj.toString());

  1. 关于String与StringBuffer的关系:String是不变的,StringBuffer是可变的。使用StringBuffer的append方法可以将新的内容追加到原有的StringBuffer对象上,而不会产生新的对象。最后,可以调用StringBuffer的toString()方法,将StringBuffer对象里面维护的字符串序列转换为String。

25.  instanceof运算符:返回一个boolean值。它的作用是判断给定的引用所指向的对象是否是某个类的实例或是某个类的子类的实例,或是是否实现了某个接口。

 

作业:p157: 1~8, p193: 11, 12, p215: 4, 10, 12

                                第八节

  1. 关于final类型的变量赋初值的问题,主要通过两种方式为final类型的变量赋初值
  1. 在声明变量的时候赋初值
  2. 在构造方法中赋初值,但需要在类的所有构造方法中都赋初值。
  1. 当final类型的属性是引用类型时,表示该引用只能指向初始赋值的对象,而不能再指向其他的对象,但该引用所指向的对象中的内容可以发生变化。、
  2. ArrayList底层是由数组实现的,当使用不带参数的构造方法生成ArrayList的对象时,底层会生成一个长度为10的数组来存储添加到ArrayList中的元素。
  3. 假如有如下的类声明:

public class Node

{

String data; //存放节点的数据本身

Node next; //存放指向下一个节点的引用

}

  1. 在main方法中定义3个Node对象:node1, node2, node3,使得node1的后继是node2,node2的后继是node3
  2. 新生成一个Node对象node4,将node4插入到node1与node2之间。
  3. 删除链表中的node4节点。
  4. 假如有如下类的声明:

 class Node2

{

Node2 prev; //指向前驱节点的引用

String data; //数据本身

Node2 next; //指向后继节点的引用

}

  1. 在main方法中定义3个Node2对象:node1, node2, node3,使得node1是node2的前驱,node2是node1的后继,node2是node3的前驱,node3是node2的后继,node1是node3的后继,构成双向循环链表。
  2. 新生成一个Node2对象node4,将node4插入到node1与node2之间。
  3. 删除链表中的node4节点。
  4. 关于ArrayList与LinkedList的比较分析:
  1. ArrayList底层采用数组实现,LinkedList底层采用双向链表实现。
  2. 当执行插入或者删除时,采用LinkedList比较好。
  3. 当执行搜索操作时,使用ArrayList比较好。
  1. 原生数据类型的包装类:Java中有8个原生数据类型,他们不是对象,集合中的方法参数都要求使用对象,因此无法将原生数据类型存储到集合中。因此,需要使用原生数据类型的包装类进行转换以便将原生数据类型存储到集合当中。
  2. 与原生数据类型所对应的包装类分别是:Integer, Long, Byte, Short, Double, Float, Character, Boolean。

 

 

                                    第九节

  1. 关于Map的迭代:Map主要有两种迭代方式,第一种是调用keySet()方法,得到Map中键的集合,然后使用Iterator遍历该集合,获取到集合中的每个键,再去调用map.get()方法,根据键获取到值;第二种方式是调用entrySet()方法,得到一个Map.Entry(这是一个内部类)对象的集合,该对象中包含了Map映射的一个键值对信息,然后使用Iterator遍历该集合,获取到集合中的每个Map.Entry对象,然后使用该Map.Entry对象的getKey()与getValue()方法得到Map的键值对信息。
  2. 同一个类的两个实例能否增加到HashSet中是由类的hashCode()与equals()方法决定的。
  3. 泛型的定义方式

public class GenericFoo<T>

{

private T foo;

}

如何实例化泛型对象

 

GenericFoo<String> foo = new GenericFoo<String>();

所谓泛型,本质上就是类型的参数化。

 

  1. 异常,错误与异常。错误是无法处理的情况,异常是可以处理的情况,程序遇到异常时,我们可以对异常进行处理,处理完毕后,程序可以继续执行而不会退出。
  2. 错误使用Error类表示,异常使用Exception类表示,这两个类都继承自Throwable父类。
  3. Java中的异常分为两大类
  1. 运行时异常(RuntimeException),又叫做非检查异常(unchecked exception)
  2. 非运行时异常,又叫做检查异常(checked exception)
  1. RuntimeException及其子类都是运行时异常,继承于Exception且不是RuntimeException子类的异常都是非运行时异常
  2. 不管运行时异常还是非运行时异常,都继承自Exception父类。
  3. 如何处理异常

try

{

//可能会发生异常的程序代码

}

catch(异常类型1 变量名)

{

//异常处理代码

}

catch(异常类型2 变量名)

{

//异常处理代码

}

10. 当try中的代码抛出了异常,则程序进入到对应的catch块中,执行catch中的代码,执行完毕后,程序继续按照正常的流程执行catch后面的代码;当try中的代码没有抛出异常,那么程序就不会进入到catch块中,在try块中的代码执行完毕后,程序将执行catch后面的代码。

11. 一旦try块中的代码抛出了异常,那么try块中该行语句后面的所有代码都不会再执行了,转而执行catch中的代码。

12. 完整的异常处理方式

 

try

{

//可能会发生异常的程序代码

}

catch(异常类型1 变量名)

{

//异常处理代码

}

catch(异常类型2 变量名)

{

//异常处理代码

}

finally

{

//无论异常发生与否,都会执行的代码,一般用于资源回收或者清理工作

                               第十节

  1. NullPointerException是最常见的一种运行时异常,出现该异常的原因是值为null的引用调用了对象的方法所导致的,如果一个引用的值为null,表示它不指向任何对象,这样我们就不能通过该引用调用对象的任何方法,一旦调用,编译可以通过,但执行的时候就会出现NullPointerException异常。
  2. 对于运行时异常,我们也可以不捕获(通常的做法也是不捕获)。
  3. 非运行时异常(检查异常)的两种处理方式:
  1. 使用try...catch进行捕获
  2. 在调用该方法的方法声明throws这个异常。
  1. 自定义异常,实际上就是定义一个继承自Exception的类,那么这个类就是一个自定义异常类。通常我们都会直接继承自Exception类,一般不会继承自某个运行时异常类。换句话说,自定义的异常一般都是非运行时异常(checked exception)
  2. 在使用自定义异常时,也可以用两种方式处理:try…catch与抛出,在抛出时,可以直接抛出产生的异常对象所属的类,也可以抛出其父类。
  3. 多线程(Multi-Thread),定义线程的第一种方式:继承Thread类并重写run方法

 

public class MyThread extends Thread

{

public void run()

{

//要执行的代码

}

}

 

启动线程的唯一方式:使用线程的start()方法,start()方法完成两件事情:

  1. 为线程准备系统资源并调度线程。
  2. 调用线程对象的run()方法。
  3. 对于单核CPU来说,线程的执行是:微观串行,宏观并行。
  4. 对于双核以上的CPU来说,线程的执行是:微观并行,宏观并行。
  5. 定义线程的第二种方式:首先定义一个实现Runnable接口的类,然后实现里面的run()方法,接下来生成该类的对象,最后将该对象作为参数传递给Thread类的构造方法中。

class MyThread implements Runnable

{

public void run()

{

//要执行的代码

}

}

 

Thread thread = new Thread(new MyThread());

thread.start();

synchronized关键字,每个对象都有一把锁,当线程访问某个synchronized方法时,它就将该方法所在的当前对象上锁,这时,其他线程就不可能再进入到该方法中,一直到第一个线程执行完该方法或者是在执行过程中抛出了异常,那么第一个线程就会释放掉该对象的锁,这时,其他的线程就可以进入到该方法中,并且立刻对该方法所属的对象上锁。