sun考试: SCJP:只考core java SCJD:+jdbc+swing
SCWCD:+servlet+jsp(JAVA EE) SCEA:+EJB+Webserver(架构师)
必须养成优秀程序员的编写习惯:缩进(用空格)、注释、命名约定。
大小写敏感。
单独的“;”代表一条空语句。
main函数是我们整个程序的执行入口所以必须是静态公开的。
必须写成这样: public static void main(String[]args){...}
生成jar包:
在eclipse里,选中要打包的几个文件,右键-Export-写文件名-Next-Next-选main方法的class-finish
在jar包的同一文件夹下,新建一个空文档,写“java -jar ./文件名.jar”,再把这文档改成“文件名.sh”
把这sh的属性-权限 改成“允许以程序执行文件”。以后双击这个sh即可运行
文本注释 Comments:
注释必须写上,以便其他人阅读、引用和维护。
单行注释 //...
多行注释 /* ....*/
文档注释 /** ... */
文档注释,可以使用JDK的javadoc工具从原文件中抽取这种注释形成程序的帮助文档。
使用javadoc命令建立HTML格式的程序文档:
javadoc[options][packagenames][sourcefiles][@files]
标示符:
用来给一个类、变量或方法命名的符号
标示符命名规则:
1. 以字母,“_”和“$”开头。可以包含字母、数字、“_”和“$”。
2. 大小写敏感
3. 不能与保留关键字冲突
4. 没有长度限制(暗示使用长的标示符,以便阅读。长名字可使用工具输入)
5. 建议使用JavaBeans规则命名,并根据方法的目的,以 set、get、is、add 或 remove 开头。
标示符命名约定:
1. 类名、接口名:每个单词的首字母应该大写,尤其第一个单词的首字母应该大写。(驼峰规则)
class MyFirstClass
interface Weapon
2. 字段、方法以及对象:第一个单词首字母应小写,其他单词首字母大写。(以便跟上面的有所区别)
boolean isWoman
void setName(String name)
3. 常量:全部用大写字母表示。如果由几个单词组成,则由下画线连接。
public final int GREEN
public final int HEAD_ COUNT
4. Java包(Package):全部用小写字母。
package java.awt.event
java.lang.System.gc(); / java.lang.Runtime.gc();
垃圾回收的建议语句,只能建议而不能强制回收
注意: System.gc(); 是静态方法,可直接调用。
java.lang.Runtime.gc(); 不是静态方法,不能直接在main方法里调用
package 包
目的:命名冲突,便于管理类
运行时,先找到包所在目录,再执行“ 包名.类名”
import 导入。导入包内的类
定义包之后,执行时:javac -d 包的路径 类名.java
java 包名.类名
import java.util.*; //表示导入java.util里面的所有类;但 import java.*; 则什么类都导不进
用“*”表示导入当前包的类,不包括子包的类(可把包看作目录)。
声明规则
* 一个源代码文件最多只能有一个公共(public)类。
* 如果源文件包含公共类,则该文件名称应该与公共类名称相同。
* 一个文件只能有一个包语句,但是,可以有多个导入语句。
* 包语句(如果有的话)必须位于源文件的第一行。
* 导入语句(如果有的话)必须位于包之后,并且在类声明之前。
* 如果没有包语句,则导入语句必须是源文件最前面的语句。
* 包和导入语句应用于该文件中的所有类。
* 一个文件能够拥有多个非公共类。
* 没有公共类的文件没有任何命名限制。
输入:使用Scanner 获取输入
在J2SE 5.0中,可以使用java.util.Scanner类别取得使用者的输入
可以使用这个工具的 next() 功能,来获取用户的输入
Scanner s = new Scanner(System.in);
System.out.printf("您输入了字符: %s \n", s.next());
System.out.printf("您输入了数字: %d \n", s.nextInt());
输入:使用 BufferedReader 取得输入//5.0之前的读取键盘的方法
BufferedReader建构时接受java.io.Reader物件
可使用java.io.InputStreamReader
例: import java.io.InputStreamReader;
import java.io.BufferedReader;
class n{
public static void main(String[] args){
System.out.println("请输入一列文字,包括空格:");
BufferedReader s = new BufferedReader(new InputStreamReader(System.in));
String next;
try{next = s.readLine();//此语句会抛异常,需处理
System.out.println("您输入了文字:" + next);
}catch(Exception e){}
}}
数值保存方式:
正数= 二进制
负数= 补码
补码= 反码 +1 正数=负数的补码(反码+1)
反码= 非(二进制数)
八进制数,零开头 011(八进制)=9(十进制)
十六进制数,零x开头 0x55(十六进制)=5*16+5(十进制)
类型:数据都必须有类型
boolean (8bit,不定的)只有true和false两个值
char 16bit, 0~2^16-1 (2^16=6万6)
byte 8bit, -2^7~2^7-1 (2^7=128; 注意:两个 byte 数相加,变 int 型)
short 16bit, -2^15~2^15-1 (2^15=32768)
int 32bit, -2^31~2^31-1 (2147483648,20亿,10位有效数字)
long 64bit, -2^63~2^63-1 (900亿亿,20位有效数字)
float 32bit, 9位有效数字,含小数(四舍五入)(小数点算一位,正负号不算)
double 64bit, 18位有效数字
注:float 和 double 的小数部分不可能精确,只能近似。
比较小数时,用 double i=0.01; if ( i - 0.01 < 1E-6) ...
不能直接 if (i==0.01)...
默认,整数是int类型,小数是double类型
long类型值,需跟L或l在数据后;float类型要跟f或F;或强制类型转换
科学计数法:12.5E3
类型转换默认序列:
byte > short > int > long > float > double
char 」
注意:默认类型转换(自动类型提升)会丢失精度,但只有三种情况:
int>float; long>float; long>double. 看一下他们的有效位就明白。
二进制是无法精确的表示 0.1 的。
进行高精度运算可以用java.math包中BigDecimal类中的方法。
自动类型提升又称作隐式类型转换。
强制类型转换:int ti; (byte) ti ;
强制转换,丢弃高位
宣告变量名称的同时,加上“final”关键词来限定,这个变量一但指定了值,就不可以再改变它的值
如:final int n1= 10; n1=20; 这就会报错
输出命令:
System.out.println() 会自动换行的打印
System.out.print() 直接打印,不会自动换行
System.out.printf() 可插入带 % 的输入类型,前两种只可以插入转义符, 不能插入 % 的数据或字符串
在 printf 里面,输出有5个部分 %[argument_index$][flags][width][.precision]conversion
以“%”开头,[第几个数值$][flags][宽度][.精确度][格式]
printf()的引入是为了照顾c语言程序员的感情需要
格式化输出 Formatter;格式化输入 Scanner;正则表达式
输出格式控制:
转义符:
\ddd 1到3位8进制数指定Unicode字符输出(ddd)
\uxxxx 1到4位16进制数指定Unicode字符输出(xxxx)
\\ \
\' '
\" "
\b 退格(光标向左走一格)
\f 走纸转页,换页
\n 换行
\r 光标回到行首,不换行
\t 跳格
%% %
%d 输出10进位整数,只能输出Byte、Short、 Integer、Long、或BigInteger类型。(输出其他类型会抛异常)
%f 以10进位输出浮点数,提供的数必须是Float、Double或 BigDecimal (输出Integer类型也抛异常)
%e,%E 以10进位输出浮点数,并使用科学记号,提供的数必须是Float、 Double或BigDecimal
%a,%A 用科学记号输出浮点数,以16进位输出整数部份,以10进位输出指数部份,数据类型要求同上。
%o (字母o)以8进位整数方式输出,限数据类型:Byte,Short,Integer,Long或BigInteger
%x,%X 将浮点数以16进位方式输出,数据类型要求同上
%s,%S 将字符串格式化输出(可输出任何类型)
%c,%C 以字符方式输出,提供的数必须是Byte、Short、Character或 Integer
%b,%B 输出"true"或"false"(%B输出"TRUE"或"FALSE");另外,非空值输出true,空值输出 false
%t,%T 输出日期/时间的前置,详请看在线API文件
/********找出各字符的Unicode值*******************/
class Test{
public static void main(String[] args) {
String s= ""+0+'a'; //0=48,9=57
//A=65,Z=90;a=97,z=122;空格=32
int i = s.codePointAt(0);
int j = s.codePointAt(1);
//利用这codePointAt(int index)方法
System.out.printf("%d %d",i,j);
}}
/**********************************************/
字符串的拼接:
字符串+数值=字符串
数值+字符串=字符串
如:str+10+20 ==str1020 而 10+20+str ==30str
"+" 和 "+=" 都被重载了,具有合并字符串的能力,相当于 String 类里的 concat();
运算:
算术运算: 加( +) 减(-) 乘( * ) 除( / ) 取余( % )
% 取余运算: 2%3=2 100%3=1
赋值运算符:
= += -= *= /= %=
(先运行完右边的,再跟左边的进行赋值运算;如 int i=10;i-=3*5;结果-5)
<<= >>=
比较、条件运算:
大于> 不小于>= 小于< 不大于<= 等于== 不等于 !=
逻辑运算:
短路运算(且 && 或 || ) 非短路运算(& | ) 反相 !
短路运算:当前面一个表达式可以决定结果时,后面的语句不用再判断。非短路运算时,还照样判断后面的
位运算:
&(AND) |(OR) ^(XOR异或) ~(补码)按位取反 = 加1再取反(全 1 的补码是-1)
移位运算:
>> << >>>
>>右移:全部向右移动,移到右段的低位被舍弃,最高位则移入原来最高位的值。右移一位相当于除2取商。
>>>同上,只是最高位移入0(不带符号)。因为最高位是符号位,所以负数跟 >> 有区别,正数没区别。
12>>>33 为12>>(33%32) = 12>>1 =6;因为int 型只有32位,认为全移走后就没意义
1 <<32 为1
instanceof():用户判断某一个对象是否属于某一个类的实例。
“==”双等于号,比较数值是否相等。还可以用于比较两个引用,看他们引用的地址是否相等。
在 Object 类里 equals() 跟“==”功能一样;但可以重载定义一个比较两者意义是否相等的方法。
在java里可以把赋值语句连在一起写,如: x=y=z=5; 这样就x,y,z都得到同样的数值 5
两个数相运算时,默认是 int 类型
如果有更高级的,就按高级的那个类型
if(其中一个是double型)double型;
else if(其中一个是float型)float型;
else if(其中一个是long型)long型;
else int 型。
选择:
if(...){...}else{...}
if(...){...}else if(...){...}
if(...){... if(...){...}}
三重以上的选择,建议使用 switch
switch(char c){
case c1: ...; break;
case c2: ...; break;
...
default :...;
} /*switch的括号里只能用 int 和 枚举类型
能隐式转换为 int 的也可以:byte,short,char,Integer,Short,Character,Byte等。
不能用 long、小数类型(float,double) 和 String。
case后的值必须是常量。而包装类变量(Integer,Character)不会被视作常量。*/
循环:
for(初始表达式; 布尔表达式 ; 步进 ) 循环语句;
跟C的 for 一样,for 的初始化条件、结束条件、增量都可以不写。
但条件判断部分只能是boolean值,所以只能是一条条件判断语句。
for 循环一般用在循环次数已知的情况。
while (<boolean expr>)...;
do...; while (<condition>); 注意:do 后最好用“{}”,while 后的分号不可忘。
break 和 continue
break 退出当前的循环体,在嵌套循环中,只退出当前的一层循环。
continue 结束当前本次循环,继续进行下一轮的循环。可以说,只是本次忽略循环内后面的语句。
continue 只能在循环体内用。break 可以用在任意代码块中,表示退出当前程序块(配合标签使用,很好用)
这两个相当于JAVA里的 goto 语句。
注意:(个人归结的)
循环体内申明的变量,在循环体结束后立即释放,循环体外无法使用。
但在另外一个循环体内可以再次申明一个跟前面同名的变量,互相不影响。
如for内定义的 i: for(int i=0;i<10;i++){...}
则在上式 for 循环结束后无法再调用 i 值,还会报错。
for(int i=0;i<10;i++){...} 和后面的 for(int i=0;i<3;i++){...} 互不影响
若想循环体外还可以调用 for 循环体内的值,应先在体外定义。
如: int i; for (i=0; i<10; i++){...} 则for 循环后再调用 i 值,其值为10
关键字列表:
abstract boolean break byte case catch char class
continue default do double else extends enum false
final finally float for if implements import instanceof
int interface long native new null package private
protected public return short static super switch synchronized
this throw throws transient true try void volatile while
Java 中 true、false不是关键字,而是boolean类型的字面量。但也不能当作变量用。
所有的关键字都是小写,friendly,sizeof不是java的关键字
保留字:const,goto :这两个已经削去意义,但同样不能用作变量名。
第三章 对象
名词
对象:
类: 一类属性相同的对象
属性:是什么样
方法:能做什么(C 中叫作函数)
对象:
声明:Student s ;
这时我们只是说明s是一个能够指向Student类型的引用(相当于C++中的指针),并没有创建一个对象。
所以我们此时不能对s做任何操作。
初始化:s = new Student();
向系统申请一块存储空间(地址空间),该地址空间保存的是一个Student类型的数据。
而s中保存的就是该地址空间的首地址。
变量:内存空间中一块具有固定长度的,用来保存数据的地址空间。(s也是一个变量)
一个对象可以有多个引用指向。
Student[] s = new Student[3] 只是相当于声明一个长度为 3 的Student类型的数组。
实例变量和局部变量
实例变量:
1、在一个类中,任何方法之外定义的变量;
2、从面向对象的思想来说我们又把实例变量看成一个类的属性。
3、实例变量在没有符初值时系统会自动帮我们做初始化:
整型数据初始化为 0,布尔型数据初始化为 false,对象类型初始化为 null。
实例变量的作用域在本类中完全有效,当被其他的类调用的时候也可能有效。
局部变量:
1、在方法内定义的变量叫局部变量。
2、局部变量使用前必须初始化,系统不会自动给局部变量做初始化。
3、局部变量的生命范围在他所在的代码块,在重合的作用域范围内不允许两个局部变量命名冲突。
注:局部变量与实例变量允许同名,在局部变量的作用域内,其优先级高于实例变量。
我们可以用 this.实例变量名 以区分局部变量。
第四章 数组
数组:
数组也是对象
数组中保存着多个相同类型的元素
数组中的每一个元素都是变量
可以创建数组对象,但数组里只能放对象的引用,不能直接放对象进去
数组的创建:
1. 声明一个int数组变量,数组变量是数组对象的遥控器
int[] nums;
2. 创建大小为7的数组,并将它赋值给变量nums
nums = new int[7];
3. 赋于int数组每一个元素一个int值
nums[0] = 6; nums[1] = 34; nums[2] = 23; nums[3] = 4;
多维数组:
1. 定义方式:type 维数 arrayName;
如: int[][] b = new int [2] [1];
2. 分配内存空间,有两种方法:
直接为每一维分配空间: int[][] a = new int[2][3];
分别为每一维分配空间 int[][] a = new int[2][ ]; //列数可以没有,行数则一定要有
a[0] = new int[3]; a[1] = new int[5]; //a[][] 看成一维数组
可以为每行设置为空间大小不同的数组。
3. 初始化,有两种方式:
先定义数组,分配空间,然后直接对每个元素进行赋值(一个个写,或用for函数)
在定义数组的同时进行初始化。
如:int a[][] = {{2,3}, {1,5}, {3,4}};
java实质上把多维数组看作一维数组,但数组里的元素也是一个数组,即数组的数组
多维数组的长度 = 行数; (a.length=行数; a[0].length=列数)
创建数组对象的另外几种方式:
Int[] nums = {6,34,23,4,15,0, 57}; (java 形式)
这方法只能在初始化定义的时候可以,以后再想定义nums={...}就不行了
Int[] nums = new int[] {6,34,23,4,15,0, 57};
这句的后一个 int[] 内不能填数字,怕人弄错数目;
这句可以先 int[] nums;以后再另外定义 nums = new int[]{...}
[]可以换换位置,如:
Int nums[]; (C 和 C++ 形式)
注意: short [] z [] []; //这是合法的,定义一个三维数组
声明数组时,不能定义其大小;只有 new 数组时可以定大小。
数组元素的默认值:
byte short int long 为 0
float double 为 0.0
char 为 ‘\0’
boolean 为 false
引用类型为null
数组的 length 属性:
表示数组的长度,是指这个数组最多能保存的元素个数
length属性只能被读取,不能被修改
java.lang.ArrayIndexOutOfBoundsException: (这是数组下标越界的报错)
随机数:
Math.random(); //可以产生随机的0~1 的小数,不需导包
java.util.Random; //可以产生更加多种的随机数
0~100的一个随机整数(包括0,但不包括100):
Double d = 100*Math.random(); int r = d.intValue(); //方法一
Random r = new Random(); int num = r.nextInt(100); //方法二;需要 import java.util.Random;
可以直接在程序中写这句,而临时导入 int i = new java.util.Random().nextInt(100);
Arrays.sort(数组名)
排序算法。需导入 impor java.util.Arrays;
数组的拷贝:
1. 用 for 语句,将数组的元素逐个赋值。直接如果直接将数组 a = 数组b;则是将b的指针赋给a
2. 用System.arraycopy();
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
src - 源数组。
srcPos - 源数组中的起始位置。
dest - 目标数组。
destPos - 目标数据中的起始位置。
length - 要复制的数组元素的数量。
如:System.arraycopy(a, 0, b, 0, a.length); //把数组 a 全部复制到数组 b 中
在java中对面向对象(OO)的要求
1.对象是客观存在的,万物皆对象。
(注:看不见的对象并不表示该对象不存在,比如说事件);
2.简单性:采用面向对象方法可以使系统各部分各司其职各尽所能。
3.复用性:对象的功能越简单其可重用性越高。
4.弱耦合性:各司其职各尽所能。
5.高内聚性:一个对象独立完成一个功能的能力
6.类是一类事务的共性,是人类主观认识的一种抽象,是对象的模板。
面向过程与面向对象的对比
面向过程:先有算法,后有数据结构。先考虑怎么做。
面向对象:先有数据结构,后有算法。先考虑用什么做。
第六章 构造方法
方法的声明(分为五个部分)
1.方法的修饰符(可以有多个,且顺序无关)
2.方法的返回值类型
3.方法名
4.方法的参数列表
如果方法有参数,一定要以正确的数量、类型、和顺序传递参数;可以将变量当作参数传入,但要类型相符
5.方法允许抛出的例外(异常)
注:编译器只能做语法上的检查,而不能进行逻辑上的检查。
Java中不允许有废话,永远不会执行的语句不允许写。
1. 声明格式:
<modifiers><return_type><name>([argument_list>])[throws <exception>]{<block>}
例如:public String getName(){return name;}
2. 当没有返回值时,返回类型必须被定义为 void。
3. 构造方法没有返回类型。
4. 返回类型必须与方法名相邻,其他修饰符号可以调换位置。
参数传递
在java方法传参过程中简单类型是按值传递,对象类型是按引用传递。
按值传递传递的是数据的副本。
按引用传递 传递的是保存该数据的地址
Java语言总是使用传值调用,这意味着方法得到的只是所有参数值的拷贝。
因此,方法不能修改传递给它的任何参数变量的内容。
对象类型的参数传递的也是该对象的引用值
方法中并不能改变对象变量,但能通过该变量调用对象的方法或修改对象的成员。
方法的参数基本上与局部变量相同,但你不需要直接初始化它
编译器会确保方法调用时会有与声明相符的参数传进来,且参数会自动被赋值
形参 VS 实参:
形参(形式参数):相当于函数(Java中也把函数称之为方法)中的局部变量
在函数被调用时创建,并以传入的实参作为起始值,函数调用结束时被释放
不会影响主程序中其他的变量(即使有变量跟他们同名),因为他们是不同作用域的变量,互不干扰。
实参:调用函数时,实际传给函数形式参数的数据。
重载(Overload)
在同一个类中,允许同时存在一个以上的同名函数,只要他们的参数列表不同即可。
参数列表不同,可以是参数的类型或个数不同,也可以是不同类型参数的顺序不同。
1、相同方法名,不同参数表。
2、方法重载时,对于参数的匹配有个向上就近原则。(这样可以节省栈空间资源);
3、为什么面向对象中要有方法重载?
方法的重载使同一类方法由于参数造成的差异对于对象的使用者是透明的。
对象的使用者只负责把参数交给对象,而具体怎么实现由对象内部决定。
4、Java中的运算符重载
java中唯一重载的运算符是String类型的“+”号,任何类型+String类型结果都为Stirng类型。
5、注意点:重载不仅出现在同一个类中,也可以出现在父子类中。
重载的方法只是刚好有相同名字的不同方法
方法的覆盖 (Override) 重写
继承之后,想改变由父类继承下来的方法。
1. 同样的方法名、参数列表、返回类型(从Java 5 起,返回类型可以是子类型)
2. 访问权限不能更小
3. 异常不能更宽 (可以抛出更少或是更窄的检查异常,或者任何非检查异常)
重构 (extract Method)
消除代码的重复,提高代码的可维护性。整理凌乱的代码,把可重用的代码块包装起来。
常用重复的方法封装成工具类(工具类太多则做成工具箱),一般都是静态方法和常量,没有属性。
在eclipse里,选中要重构的代码,右键Refactor-Extract Mathod 或(Shift+Alt+M)
创建对象的步骤
1、分配空间
2、初始化属性
3、调用构造方法
注:构造方法不能手工调用,在对象的生命周期内构造方法只调用一次。
构造方法 (参考day05的 TestCat.java)
构造方法是在生成对象的过程中调用的方法,但构造方法并不能创建对象。
new 对象的时候需要调用构造方法。
1、特点:没有返回值(连void也没有),方法名与类名相同。(如果加上 void 会变成普通方法。)
2、在不写构造方法时,系统会自动生成一个无参的构造方法。
3、请养成在每个类中自己加上无参构造方法的习惯。
格式为:public ClassName(){}
构造方法也可以是其他的限制符――private protected default
private 一般用在 singleton 模式中。
在一个对象的生成周期中构造方法只用一次,一旦这个对象生成,那么这个构造方法失效。
* 接口不能创建实例,因为没有构造方法
可以构造多个构造方法,但多个构造方法的参数表一定不同,或参数顺序不同
即属于不同的构造方法:-----------------------> 构造方法的重载
使用构造方法来初始化对象的状态:把初始化代码放到构造方法中,并且把构造方法设定成需要参数的
编译器一定会帮你写出没有参数的构造方法吗?不会
如果你已经写了一个有参数的构造方法,并且你需要一个没有参数的构造方法,则你必须自己动手写
如果类有一个以上的构造方法,则参数列表一定要不一样,我们可以认为这几个构造方法形成重载关系
如果我们提供了有参的构造方法,那么系统不会再提供无参的构造方法了。
这样当被子类继承时,如果子类构造方法不人为调用父类的有参构造方法就会出现异常。
构造方法可以通过 this 调用另外一个构造方法(this 此时必须在第一行语句)
匿名对象:
创建对象时,直接调用对象的方法而不定义对象的句柄。
如: person p1 = new person; p1.shout();
改写成: new person.shout(); //此方法执行完,此匿名对象也就变成了垃圾。
使用匿名对象的情况:
1. 此对象只需要一次方法调用。
2. 此对象作为实参传给一个函数调用。
this 当前对象 (参考day05 的TestThis.java)
谁调用该方法,在这一时刻谁就是该方法的当前对象;是个隐式参数,代表被构造的对象。
用this来区分实例变量和局部变量。
this.实例变量名 = 局部变量名 (将局部变量赋值给实例变量)
this()表示调用本类的其他构造方法,且只能放在一个方法中的第一行第一句。
构造方法可以通过this调用另外一个构造方法(this此时必须在第一行语句)
*super 关键字也是个隐形参数,代表被构造对象的父类。
同样也必须在构造方法的第一行
对象和对象引用的区别
对象好比一台电视机,对象引用好比电视机遥控。对象引用 中存的是对象的地址。
多个对象引用中存放的是同一个地址,表示该对象被多个对象引用所引用。
面向对象的三大特性:
封装(Encapsulation)、继承(Inheritance)、多态polymiorphism
封装:
1.定义:指一个对象的内部状态对外界是透明的,对象与对象之间只关心对方有什么方法,而不关心属性。
封装使实现的改变对架构的影响最小化。封装后的代码更具有安全性、可扩展性和可维护性。
2.原则:封装使对象的属性尽可能的私有,根据需要配上相应的get/set方法,对象的方法尽可能的公开。
该隐藏的一定要隐藏,该公开的一定要公开。
3.方法公开的是声明而不是实现。使方法实现的改变对架构的影响最小化。
4.访问权限控制从严到宽
private :仅本类成员可见
default :本类+同包类可见(默认)
protected:本类+同包+不同包的子类
public :公开
注:这里的同包指的是跟父类所在的包相同。
5、完全封装:属性全部私有,并提供相应的get/set方法。
优点:
1.事物的内部实现细节隐藏起来
2.对外提供一致的公共的接口――间接访问隐藏数据
3.可维护性
一、继承:
1 定义:基于一个已存在的类构造一个新类。
继承已存在的类就是复用这些类的方法和属性,在此基础上,还可以在新类中添加一些新的方法和属性。
2 父类到子类是从一般到特殊的关系。
3 继承用关键字extends
dog extends Animal :表示狗类继承了动物类
4 Java中只允许单继承(java简单性的体现)
父子类之间的关系是树状关系。(而多继承是网状关系)
5 父类中的私有属性可以继承但是不能访问。
也可以说父类中的私有属性子类不能继承。
6 原则:父类放共性,子类放个性。
7 构造方法不能被子类继承。
父类的成员能否继承到子类?
private:本类内部可以访问 不能继承到子类
(default):本类内部可以访问,同包其他类也可以访问
能否继承到子类? 不一定:同包的可继承,不同包则不可继承。
protected:本类内部可以访问,不同包的子类也可以访问, 同包其他类也可以访问
能继承到子类
public:任何地方都可以访问 能继承到子类
继承的意义:
1. 避免了重复的程序代码,提高了程序的可重用性
2. 定义出共同的协议
二、带继承关系的对象创建的过程
1.递归的构造父类对象
2.分配空间
3.初始化属性
4.调用本类的构造方法
三、super 关键字
1.super()表示调用父类的构造方法
2.super()也和this一样必须放在构造方法的第一行第一句。不是构造方法则不用第一行。
3.super.表示调用父类的方法或属性。例:super.m();
4.super 可以屏蔽子类属性和父类属性重名时带来的冲突
5.在子类的构造函数中如果没有指定调用父类的哪一个构造方法,就会调用父类的无参构造方法,即super()
指向父类的引用
super.age
super.addAge()
调用父类的构造方法
super();
super(“wangcai”,8);
一个对象的创建过程
1. 当构造一个对象的时候,系统先构造父类对象,再构造子类对象。
2. 构造一个对象的顺序:(注意:构造父类对象的时候也是这几步)
递归地创建父类的 static 成员(即使只调用其子类静态成员,也会先创建父类静态成员);
顺序地创建本类的 static 成员(只要调用这个类的属性或方法都需创建一次);
递归地创建父类对象(先创建父类非静态成员,再调用父类构造方法);
顺序地创建本类非静态成员(包括属性和方法);
调用本类的构造方法(它可调用本类或父类的成员,也可调用本类的其他构造方法)。
创建完成了(更多详情参看下面:类加载的顺序)
四、白箱复用和黑箱复用
1.白箱复用:又叫继承复用,子类会继承父类所有的东西,
从某种程度上说白箱复用破坏了封装。是一种 is a 的关系。
例:class Liucy{
public void teachCpp(){System.out.println("Teach Cpp");}
public void chimogu(){ }
}
class Huxy extends Liucy{}
2、黑箱复用:又叫组合复用,是一种 has a 的关系。
例:class Liucy{
public void teachCpp(){System.out.println("Teach Cpp");}
public void chimogu(){ }
}
class Huxy {
private Liucy liucy = new Liucy();
public void teachCpp(){liucy.teachCpp();}
}
原则:组合复用取代继承复用原则。
使我们可以有机会选择该复用的功能。
多态
1.定义:是指一个对象可以有多种形态,换句话说多态使我们可以把一个子类对象看作是一个父类对象类型
(例:father A = new child() )。
多态指的是编译时的类型变化,而运行时类型不变。
2.多态分为两种:编译时多态和运行时多态。
编译时类型:定义时类型(主观概念)把它看作什么。
运行时类型:真实类型(客观概念) 实际上他是什么。
重载是编译时多态,覆盖是运行时多态。在方法重载的情况下,参数类型决定于编译时类型。
3.作用:在需要一类对象的共性时,可以很容易的抽取。并且可以屏蔽不同子类对象之间所不关心的差异。
多态方便写出更通用的代码,以适应需求的不断变化
4.多态常见的用法:
(1)、多态用在方法的参数上
(2)、多态用在方法的返回类型上
5.运行时多态的三原则:
(1)、对象不变(改变的是主观认识)
(2)、对于对象的调用只能限于编译时类型的方法。
(3)、在程序的运行时,动态类型判定。运行时调用运行时类型,即他调用覆盖后的方法。
注意:多态时,只有一般方法是动态调用的;而 static 方法和 final 方法依然是静态调用的;属性全是静态调用的。
如:father A = new child(); 则A的一般方法是child的方法;但A的属性是father的属性。
同样:child C = new child(); 则 (father)C 的一般方法还是child的方法,但属性是father的属性。
if(cat instanceof Animal){ ... } //如果cat属于Animal类型则执行
强制类型转换,在迫不得已的时候再用。因为很容易出错。
第八章:高级语言特性
静态变量 static
一个类只有一个静态变量,跟对象没有关系。被类的所有实例共享;如果子类没有覆盖,也共享父类的静态成员。
一般直接使用类名来访问 “类名.静态变量名”。可以在没有任何实例时调用。
在某种意义上类似于全局变量(Java里没有全局变量,这只是C和C++的说法)
不能在 static 方法或代码块里访问非 static 成员(变量或方法)
能继承和覆盖,但覆盖 static 方法必须也是 static 的方法。
1.可以修饰属性、方法、初始代码块,成为类变量、静态方法、静态初始化代码块。
注:初始代码块是在类中而不是在任何方法之内的代码块。
2.类变量、静态方法、静态初始化代码块与具体的某个对象无关,只与类相关,是全类公有的。 在类加载时初始化。
3.类加载:JVM通过CLASSPATH找到字节码文件,并将字节码文件中的内容通过I/O流读到JVM并保存的过程
在虚拟机的生命周期中一个类只被加载一次。
注:Java命令的作用是启动JVM (Java Virtual Mechine)。
4.tatic 定义的是一块为整个类共有的一块存储区域,其发生变化时访问到的数据都是经过变化的。
5.为什么主方法必须是静态的?
主方法是整个应用程序的入口,JVM只能通过类名去调用主方法。
6.类变量和静态方法可以在没有对象的情况下用:类名.方法名(或属性名)来访问。
7.静态方法不可被覆盖(允许在子类中定义同名的静态方法,但是没有多态)
父类如果是静态方法,子类不能覆盖为非静态方法。父类如果是非静态方法,子类不能覆盖为静态方法。
争论:静态方法可以覆盖但是没有多态。
思考:没有多态的覆盖叫覆盖吗?
在静态方法中不允许调用本类中的非静态成员。
8.静态初始化代码块只在类加载的时候运行一次,以再也不执行了。所以静态代码块一般被用来初始化静态成员。
9.不加static为动态初始化代码块,在创建对象时被调用(在构造函数之前)。
10.最后要注意的一点就是 static 不能修饰局部变量。
什么时候类加载
第一次需要使用类信息时加载。
类加载的原则:延迟加载,能不加载就不加载。
触发类加载的几种情况:
(1)、调用静态成员时,会加载静态成员真正所在的类及其父类。
通过子类调用父类的静态成员时,只会加载父类而不会加载子类。
(2)、第一次 new 对象的时候 加载(第二次再 new 同一个类时,不需再加载)。
(3)、加载子类会先加载父类。
注:如果静态属性有 final 修饰时,则不会加载,当成常量使用。
例:public static final int a =123;
但是如果上面的等式右值改成表达式(且该表达式在编译时不能确定其值)时则会加载类。
例:public static final int a = math.PI
如果访问的是类的公开静态常量,那么如果编译器在编译的时候能确定这个常量的值,就不会被加载;
如果编译时不能确定其值的话,则运行时加载
类加载的顺序:
1.加载静态成员/代码块:
先递归地加载父类的静态成员/代码块(Object的最先);再依次加载到本类的静态成员。
同一个类里的静态成员/代码块,按写代码的顺序加载。
如果其间调用静态方法,则调用时会先运行静态方法,再继续加载。同一个类里调用静态方法时,可以不理会写代码的顺序。
调用父类的静态成员,可以像调用自己的一样;但调用其子类的静态成员,必须使用“子类名.成员名”来调用。
2.加载非静态成员/代码块:
先递归地加载父类的非静态成员/代码块(Object的最先);再依次加载到本类的非静态成员。
同一个类里的非静态成员/代码块,按写代码的顺序加载。同一个类里调用方法时,可以不理会写代码的顺序。
但调用属性时,必须注意加载顺序。一般编译不通过,如果能在加载前调用,值为默认初始值(如:null 或者 0)。
调用父类的非静态成员(private 除外),也可以像调用自己的一样。
3.调用构造方法:
先递归地调用父类的构造方法(Object的最先);默认调用父类空参的,也可在第一行写明调用父类某个带参的。
再依次到本类的构造方法;构造方法内,也可在第一行写明调用某个本类其它的构造方法。
注意:如果加载时遇到 override 的成员,可看作是所需创建的类型赋值给当前类型。
其调用按多态用法:只有非静态方法有多态;而静态方法、静态属性、非静态属性都没有多态。
假设子类override父类的所有成员,包括静态成员、非静态属性和非静态方法。
由于构造子类时会先构造父类;而构造父类时,其所用的静态成员和非静态属性是父类的,但非静态方法却是子类的;
由于构造父类时,子类并未加载;如果此时所调用的非静态方法里有成员,则这个成员是子类的,且非静态属性是默认初始值的。
成员,包括变量和方法
成员变量,包括实例变量和静态变量
final 修饰符
(最终的、最后的)当final修饰时,不能被改变,不能被继承
1.final 可以用来修饰类、属性和方法、局部变量。
2.final 修饰一个属性时,该属性成为常量。
(1)对于在构造方法中利用final进行赋值时,此时在构造之前系统设置的默认值相对于构造方法失效。
(2)对于实例常量的赋值有两次机会
在初始化的时候通过声明赋值
在构造的时候(构造方法里)赋值
注:不能在声明时赋值一次,在构造时再赋值一次。
注意:当final修饰实例变量时,实例变量不会自动初始化为0;但必须给他赋值才能通过编译。
3.final 修饰方法时,该方法成为一个不可覆盖的方法。这样可以保持方法的稳定性。
如果一个方法前有修饰词private或static,则系统会自动在前面加上final。
即 private 和 static 方法默认均为 final 方法。
4.final 常常和 static、public 配合来修饰一个实例变量,表示为一个全类公有的公开静态常量。
例: public static final int a = 33;
在这种情况下属性虽然公开了,但由于是一个静态常量所以并不算破坏类的封装。
5.final 修饰类时,此类不可被继承,即final类没有子类。
一个 final 类中的所有方法默认全是final方法。
final 不能修饰构造方法,构造方法不能被继承更谈不上被子类方法覆盖。
关于 final 的设计模式:不变模式
1、不变模式:一个对象一旦产生就不可能再修改( string 就是典型的不变模式);
通过不变模式可以做到对象共享;
2、池化思想:用一个存储区域来存放一些公用资源以减少存储空间的开销。
有池的类型:boolean,byte,int,short,long,char,(池范围在-127~128之间)
(float,double 等小数没有池)
例:在String类中有个串池(在代码区)。
池:堆里的一片独立空间。目的是拿空间换时间,让运算效率更高。
(1)如果用Stirng str = “abc” 来创建一个对象时,则系统会先在“串池”中寻找有没有“abc”这个字符串
如果有则直接将对象指向串池中对应的地址,如果没有则在串池中创建一个“abc”字符串。
所以:String str1 = “abc”;
String str2 = “abc”;
Str1 == str2 返回值是ture;他们的地址是一样的。
也就是说str1和str2都指向了代码空间中相同的一个地址,而这个地址空间保存就是是字符串"abc"
字符串是不可改变的类型,所以可以共享。所以串池里不会有相同的两个字符串。
(2)如果用String str = new String("abc")则直接开辟一块内存放"abc"这个字符串。
所以上面这语句,创建两个"abc",一个在池,一个是对象
String str2 = new String("abc");
Str == str2 返回值是false;他们的地址是不一样的。
即是说str和str2分别指向了堆空间中不同的两个地址,而这两个地址空间保存的都是字符串"abc"
StringBuffer 类(java.lang下的)。
对于字符串连接
String str=”1”+”2”+”3”+”4”;
产生:
12 123 1234
这在串池中产生多余对象,而我们真正需要的只有最后一个对象,这种方式在时间和空间上都造成相当大的浪费。
所以我们应该使用 StringBuffer(线程安全的) 或者 StringBuilder(线程不安全的)来解决
解决方案:
StringBuffer sb = new StringBuffer(“1”);
Sb.append(“2”);
Sb.append(“3”);
Sb.append(“4”);
S = sb.toString();
解决后的方案比解决前在运行的时间上快2个数量级。
StringBuilder (1.5版本后出现的)
线程不安全的,在多线程并发时会出现问题。但仍是字符串合并的首选。
运行效率比 StringBuffer 快一倍。
abstract 抽象
1.可用来修饰类、方法
2.abstract 修饰类时,则该类成为一个抽象类。
抽象类不可生成对象(但可以有构造方法留给子类使用),必须被继承使用。
抽象类可以声明,作为编译时类型,但不能作为运行时类型。
abstract 永远不会和 private,static,final 同时出现。( 因为抽象必须被继承。)
3.abstract 修饰方法时,则该方法成为一个抽象方法,抽象方法不能有实现;由子类覆盖后实现。
比较:private void print(){};表示方法的空实现
abstract void print();表示方法为抽象方法,没有实现
4.抽象方法从某中意义上来说是制定了一个标准,父类并不实现,留给子类去实现。
注:抽象类中不一定要有抽象方法,但有抽象方法的类一定是抽象类。
抽象类可以有抽象方法和非抽象方法。实现抽象类的第一个具体类必须实现其所有抽象方法。
5.关于抽象类的设计模式:模板方法
灵活性和不变性
interface 接口
1、定义:接口不是类,而是一组对类需求的描述,这些类要遵从接口描述的统一格式进行定义。
定义一个接口用关键字 interface。
例:public interface a{……}
2、接口是一种特殊的抽象类。
在一个接口中,所有的方法为公开、抽象的方法,所有的属性都是公开、静态、常量。
所以接口中的所有属性可省略修饰符:public static final。也只能用这三个修饰符。
接口中所有的方法可省略修饰符:public abstract。但这些都是默认存在的。
3、一个类实现一个接口必须实现接口中所有的方法,否则其为一抽象类。而且实现类的方法需要 public
实现接口用关键字 implements.
所谓实现一个接口就是实现接口中所有的方法。
例:class Aimple implements A{……..};
4、一个类除了继承另一个类外(且只能继承一个类),还可以实现多个接口(接口之间用逗号分割)。
接口可以实现变相的多继承。
例:class Aimple extends Arrylist implements A,B,C{…}
5、不能用“new 接口名”来实例化一个接口,但可以声明一个接口。
6、接口与接口之间可以多继承。
例:interface face1 extends face2,face3{}
接口的继承相当于接口的合并
7、接口的作用
(1)、间接实现多继承。
用接口来实现多继承并不会增加类关系的复杂度。因为接口不是类,是在类的基础上的再次抽象。
父类:主类型 接口:副类型
典例:父亲(主) 和 老师(副)
(2)、允许我们为一个类定义出混合类型。
(3)、通过接口制定标准
接 口:标准的定义 定义标准
接口的调用者:标准的使用 使用标准
接口的实现类:标准的实现 实现标准
接口的回调:先有接口的使用者,再有接口的实现者,最后把接口的实现者的对象传到接口的使用者中,
并由接口的使用者通过接口来调用接口实现者的方法。
例:sun公司提供一套访问数据库的接口(标准),java程序员访问数据库时针对数据库接口编程。
接口由各个数据库厂商负责实现。
(4)、解耦合作用:采用接口可以最大限度的做到弱耦合,将标准的实现者与标准的制定者隔离
(例:我们通过JDBC接口来屏蔽底层数据库的差异)
8、接口的编程设计原则
(1)、尽量针对接口编程(能用接口就尽量用接口)
(2)、接口隔离原则(用若干个小接口取代一个大接口)
这样可以只暴露想暴露的方法,实现一个更高层次的封装。
9、注意点:
(1)、一个文件只能有一个 public 接口,且与文件名相同。
(2)、在一个文件中不能同时定义一个 public 接口和一个 public 类。
(3)、接口与实体类之间只有实现关系,没有继承关系;
抽象类与类之间只有继承关系没有实现关系。接口与接口之间只有继承关系,且允许多继承。
(4)、接口中可以不写 public,但在子类实现接口的过程中 public 不可省略。
接口 VS 抽象类
1、接口中不能有具体的实现,但抽象类可以。
2、一个类要实现一个接口必须实现其里面所有的方法,而抽象类不必。
3、通过接口可以实现多继承,而抽象类做不到。
4、接口不能有构造方法,而抽象类可以。
5、实体类与接口之间只有实现关系,而实体类与抽象类只有继承关系
抽象类与接口之间既有实现关系又有继承关系。
6、接口中的方法默认都是公开抽象方法,属性默认都是公开静态常量,而抽象类不是。
修饰符的使用情况:
(Y表可用;不写表示不可用)
修饰符 类 属性 方法 局部变量(所有局部变量都不能用修饰符)
public Y Y Y
protected Y Y
(default) Y Y Y
private Y Y
static Y Y
final Y Y Y Y
abstract Y Y
访问权限控制:
修饰符 同一个类 同一个包 (不同包)子类 其他包
public Y Y Y Y
protected Y Y Y
(default) Y Y
private Y
Object类
1、object类是类层次结构的根类,他是所有类默认的父类。
2、object类中的其中三个方法。
(1)、finalize()
当一个对象被垃圾收集的时候,最后会由JVM调用这个对象的finalize方法;
注意:这个方法一般不用,也不能将释放资源的代码放在这个方法里;只有调用C程序时,才可能要用到
(2)、toString()
存放对象地址的哈希码值。
返回一个对象的字符串表示形式。打印一个对象其实就是打印这个对象toString方法的返回值。
可以覆盖类的toString()方法,从而打印我们需要的数据。 Public String toString(){……}
(3)、equals(Object obj)
用来判断对象的值是否相等。前提是覆盖了equals方法。Object类中的equals方法判断的依然是地址
注意:String类已经覆盖了equals方法,所以能用equals来判断String对象的值是否相等。
下面是覆盖equals方法的标准流程:
/*************************************************************************/
public boolean equals(Object obj){
//第一步:现判断两个对象地址是否相等
if(this == obj) return true;
//第二步:如果参数是null的话直接返回false;
if(obj == null) return false;
//第三步:如果两个对象不是同一个类型直接返回false
if (getClass() != obj.getClass()) return false;
//?? if(!(this.getClass.getName().equals(o.getClass.getName())) return false;
//第四步:将待比较对象强转成指定类型,然后自定义比较规则
Student s = (Student) obj;
if(s.name.equals(this.name)&&s.age==this.age) return true;
else return false;
}
/*************************************************************************/
覆盖equals的原则: 1.自反性(自己=自己)、 2.对称性(y=x则x=y)、
3.一致性(多次调用,结果一致)、 4.传递性(A=B,B=C则A=C)。
非空原则: t1.equals(Null)返回False;(如果t1不等于空)
(4)、clone 克隆,拷贝
一个对象参与序列化过程,那么对象流会记录该对象的状态,当再次序列化时,
会重复序列化前面记录的对象初始状态,我们可以用对象克隆技术来解决这个问题
1 类中覆盖父类的clone方法,提升protected为public
2 类实现Cloneable接口
浅拷贝:只简单复制对象的属性
深拷贝:如果被复制对象的属性也是一个对象,则还会复制这个属性对象
这种复制是一个递归的过程,通过对象序列化实现
《Java5.0新特性》
四大点(枚举、泛型、注释、..);5 小点(包装类、静态应用、可变长参数、for-each、..)
一、自动装箱 和 自动解箱技术
装箱Autoboxing,也翻译作 封箱;解箱Unautoboxing(也译作 解封)
1、自动装箱技术:编译器会自动将简单类型转换成封装类型。
2、编译器会自动将封装类型转换成简单类型
3、注意:自动装箱和自动解箱只会在必要的情况下执行。
int 能隐式提升成 long;但Integer不能隐式提升成Long,只能提升成Number
封装之后就成类,只能由子类转成父类;而Integer和Long是Number的不同子类。
如: int i; short s; Integer II; Short SS;
可以 i=SS; 但不可以 II=s; //赋值时,右边的数先转成左边数的对应类型,再进行隐式类型提升
二、静态引用概念:
用 import static 节省以后的书写。
引入静态属性 import static java.lang.System.out;
引入静态方法 import static java.lang.Math.random;
import static 只能引入静态的方法或属性;不能只引入类或非静态的方法。
如:import static java.lang.System.*;
out.println(“a”); //等于System.out.println("a"); 由于out是一个字段,所以不能更节省了
如果 import static java.lang.System.gc; 则可以直接在程序中用 gc(); //等于System.gc();
三、可变长参数
一个方法的参数列表中最多只能有一个可变长参数,而且这个变长参数必须是最后一个参数
方法调用时只在必要时去匹配变长参数。
/**********变长参数的例子*************************************/
import static java.lang.System.*;//节省书写,System.out直接写out
public class TestVararg {
public static void main(String... args){
m();
m("Liucy");
m("Liucy","Hiloo");
}
static void m(String... s){out.println("m(String...)");}
//s可以看作是一个字符串数组String[] s
static void m(){out.println("m()");}
static void m(String s){out.println("m(String)");}
} //m(String... s) 是最后匹配的
/**********************************************************/
四、枚举 enum
1、定义:枚举是一个具有特定值的类型,对用户来说只能任取其一。
对于面向对象来说时一个类的对象已经创建好,用户不能新生枚举对象,只能选择一个已经生成的对象。
2、枚举本质上也是一个类。枚举值之间用逗号分开,以分号结束(如果后面没有其他语句,分号可不写)。
3、枚举分为两种:类型安全的枚举模式和类型不安全的枚举模式
4、枚举的超类(父类)是:Java.lang.Enum。枚举是 final 类所以不能继承或被继承。但可以实现接口。
枚举中可以写构造方法,但构造方法必需是私有的,而且默认也是 私有的 private
5、一个枚举值实际上是一个公开静态的常量,也是这个类的一个对象。
6、枚举中可以定义抽象方法,但实现在各个枚举值中(匿名内部类的方式隐含继承)
由于枚举默认是 final 型,不能被继承,所以不能直接用抽象方法(抽象方法必须被继承)
在枚举中定义抽象方法后,需要在自己的每个枚举值中实现抽象方法。
枚举是编译期语法,编译后生成类型安全的普通类
values()静态方法,返回枚举的元素数组
name方法
/**********************************************************/
final class Season1{ //用 final 不让人继承
private Season1(){} //用 private 构造方法,不让人 new 出来
public static final Season1 SPRING=new Season1("春");
public static final Season1 SUMMER=new Season1("夏");
public static final Season1 AUTUMN=new Season1("秋");
public static final Season1 WINTER=new Season1("冬");
String name; //将"春夏秋冬"设为本类型,而不是24种基本类型,为防止值被更改
private Season1(String name){
this.name=name;
}
public String getName(){
return this.name;
}}
/********上面是以前版本时自定义的枚举,下面是新版的枚举写法********/
enum Season2{
SPRING("春"), SUMMER("夏"), AUTUMN("秋"), WINTER("冬");
String name;
Season2(String name){ this.name=name; }
public String getName(){return this.name;}
}//注意:枚举类是有序的;如:Season2.SPRING.ordinal()
/**********************************************************/
/*******关于枚举的例子****************************************/
import static java.lang.System.*;
public class TestTeacher {
public static void main(String[] args) {
for(TarenaTeacher t:TarenaTeacher.values()){
t.teach();
}}}
enum TarenaTeacher{
LIUCY("liuchunyang"){void teach(){out.println(name+" teach UC");}},
CHENZQ("chenzongquan"){void teach(){out.println(name+" teach C++");}},
HAIGE("wanghaige"){void teach(){out.println(name+" teach OOAD");}};
String name;
TarenaTeacher(String name){this.name=name;}
abstract void teach();
}
/**********************************************************/
enum Animals {
DOG ("WangWang") , CAT("meow") , FISH("burble");
String sound;
Animals ( String s ) { sound = s; }
}
class TestEnum {
static Animals a;
public static void main ( String[] args ) {
System.out.println ( a.DOG.sound + " " + a.FISH.sound );
}}
/**********************************************************/
五、新型 for 循环 for—each,用于追求数组与集合的遍历方式统一
1、数组举例:
int[] ss = {1,2,3,4,5,6};
for(int i=0; i<ss.length; i++){
System.out.print(ss[i]);
} //以上是以前的 for 循环遍历,比较下面的for—each
System.out.println();
for(int i : ss){
System.out.print(i);
2、集合举例:
List ll = new ArrayList();
for(Object o : ll ){
System.out.println(o);
}
注:凡是实现了java.lang.Iterable接口的类就能用 for—each遍历
用 for—each时,不能用list.remove()删除,因为他内部的迭代器无法调用,造成多线程出错。
这时只能用 for 配合迭代器使用。
六、泛型 Generic
1、为了解决类型安全的集合问题引入了泛型。
泛型是编译检查时的依据,也是编译期语法。
(编译期语法:编译期有效,编译后擦除,不存在于运行期)
2、简单的范型应用:集合(ArrayList, Set, Map, Iterator, Comparable)
List<String> l = new ArrayList<String>();
<String>:表示该集合中只能存放String类型对象。
3、使用了泛型技术的集合在编译时会有类型检查,不再需要强制类型转换。
String str = l.get(2); //因为List<String> l, 所以 Error
注:一个集合所允许的类型就是这个泛型的类型或这个泛型的子类型。
4、List<Number> l = new ArrayList<Integer> //Error
List<Integer> l = new ArrayList<Integer> //Right
必须类型一致,泛型没有多态
5、泛型的通配符<?>
泛型的通配符表示该集合可以存放任意类型的对象。但只有访问,不可以修改。
static void print( Cllection<?> c ){
for( Object o : c )
out.println(o);
}
6、带范围的泛型通配符
泛型的声明约定T表示类型,E表示元素
(1)、上界通配符,向下匹配:<? extends Number> 表明“extends”或“implements”,认为是 final 的
表示该集合元素可以为Number类型及其子类型(包括接口),例如 Number,Integer,Double
此时集合可以进行访问但不能修改。即不允许调用此对象的add,set等方法;但可以使用 for-each 或 get.
(2)、下界通配符,向上匹配:<? super Number>
表示该集合元素可以为Number类型及其父类型,直至 Object。
可以使用 for-each,add,addAll,set,get等方法
(3)、接口实现:<? extends Comparable>
表示该集合元素可以为实现了Comparable接口的类
7、泛型方法
在返回类型与修饰符之间可以定义一个泛型方法,令后面的泛型统一
这里只能用 extends 定义,不能用 super ;后面可以跟类(但只能有一个,且要放在首位)其余是接口
符号只有 & //“&”表示“与”;逗号表示后面的另一部分
静态方法里面,不能使用类定义的泛型,只能用自己定义的;因为静态方法可以直接调用;
所以普通方法可以使用类定义的及自己定义的泛型
public static <T> void copy(T[] array,Stack<T> sta){……}
public static <T,E extends T> void copy (T[] array,Stack<E> sta){…..}
public static <T extends Number&Comparable> void copy(List<T> list,T[] t);
8、不能使用泛型的情况:
(1)、带泛型的类不能成为 Throwable 类和 Exception 类的子类
因为cathc()中不能出现泛型。
(2)、不能用泛型来 new 一个对象
如:T t = new T();
(3)、静态方法不能使用类的泛型,因为静态方法中没有对象的概念。
9、在使用接口的时候指明泛型。
class Student implements Comparable<Student>{…….}
10、泛型类
/********************************************************************/
class MyClass<T>{
public void m1(T t){}
public T m2(){
return null;
}}
/********************************************************************/
第九章:
内部类(nested classes) (非重点)
1.定义:定义在其他类中的类,叫内部类(内置类)。内部类是一种编译时的语法,编译后生成
的两个类是独立的两个类。内部类配合接口使用,来强制做到弱耦合(局部内部类,或私有成员内部类)。
2.内部类存在的意义在于可以自由的访问外部类的任何成员(包括私有成员),但外部类不能直接访问内部类的
成员。所有使用内部类的地方都可以不使用内部类;使用内部类可以使程序更加的简洁(但牺牲可读性),
便于命名规范和划分层次结构。
3.内部类和外部类在编译时是不同的两个类,内部类对外部类没有任何依赖。
4.内部类可用 static,protected 和 private 修饰。(而外部类只能使用 public 和 default)。
5.内部类的分类:成员内部类、局部内部类、静态内部类、匿名内部类。
(注意:前三种内部类与变量类似,可以对照参考变量)
① 成员内部类(实例内部类):作为外部类的一个成员存在,与外部类的属性、方法并列。
成员内部类可看作外部类的实例变量。
在内部类中访问实例变量:this.属性
在内部类访问外部类的实例变量:外部类名.this.属性。
对于一个名为outer 的外部类和其内部定义的名为inner 的内部类。
编译完成后出现outer.class 和outer$inner.class 两类。
不可以有静态
core java有中文版吗 core java开发
转载本文章为转载内容,我们尊重原作者对文章享有的著作权。如有内容错误或侵权问题,欢迎原作者联系我们进行内容更正或删除文章。
提问和评论都可以,用心的回复会被更多人看到
评论
发布评论
相关文章