NO.1
泛型是一种机制,<>里面的参数必须是包装类; 其次,<>里面的参数可以用具体的类来表示,比如Object,String;也可以使用随意的一个符号来表示, 比如T,他表示他可以接受所以的类型; 第三,所有的泛型?泛型不分种类,只是<>里面的参数不同而已. NO.2
abstract (关键字) 抽象
access vt.访问,存取 ['?kses]'(n.入口,使用权)
algorithm n.算法
Annotation [java] 代码注释
anonymous adj.匿名的(反义:directly adv.直接地,立即[di'rektli, dai'rektli])
apply v.应用,适用
application n.应用,应用程序 (application crash 程序崩溃)
arbitrary a.任意的
argument n.参数;争论,论据 (缩写 args)
assert (关键字) 断言 (java 1.4 之后成为关键字)
associate n.关联(同伴,伙伴)
attribute n.属性(品质,特征)
boolean (关键字) 逻辑的, 布尔型
call n.v.调用; 呼叫;
circumstance n.事件(环境,状况)
crash n.崩溃,破碎
cohesion 内聚,黏聚,结合
(a class is designed with a single, well-focoused purpose. 应该不止这点)
command n. 命令,指令 (指挥, 控制) (command-line 命令行)
Comments [java] 文本注释
compile [java] v.编译 Compilation n.编辑[,k?mpi'lei??n]
const (保留字)
constant n. 常量, 常数, 恒量
continue (关键字)
coupling 耦合,联结
making sure that classes know about other classes only through their APIs.
declare [java] 声明
default (关键字) 默认值; 缺省值
delimiter 定义符; 定界符
Encapsulation[java] 封装 (hiding implementation details)
Exception [java] 例外; 异常
entry n.登录项, 输入项, 条目['entri]
enum (关键字)
execute vt.执行 ['eksikju:t]
exhibit v.显示, 陈列 [ig'zibit]
exist 存在, 发生 [ig'zist] '(SQL关键字 exists)
extends (关键字) 继承、扩展 [ik'stend]
false (关键字)
final (关键字) finally (关键字)
fragments 段落; 代码块
FrameWork [java] 结构,框架
Generic [java] 泛型
goto (保留字) 跳转
heap n.堆 [hi:p]
implements (关键字) 实现
import (关键字) 引入(进口,输入)
Info n.信息 (information )
Inheritance [java] 继承 (遗传,遗产)
initialize 预置 初始化
instanceof (关键字) 运算符,用于引用变量,以检查这个对象是否是某种类型。返回 boolean 值。
interface (关键字) 接口
invoke vt.调用 ( invocation)
Iterator [java] 迭代器, 迭代程序
legal 合法的
log n.日志,记录
native (关键字) ?? ['neitiv]
nested [java] 嵌套的 ['nestid] '如:内部类(nested classes)
Object [java] 对象 ['?bd?ekt]
Overload [java] 方法的重载(不同参数列表的同名方法)
Override [java] 方法的覆盖(覆盖父类的方法)
polymiorphism[java] 多态 (polymorphism 多形性)
allowing a single object to be seen as having many types.
principle n.原则,原理,主义 ['prinsipl]
priority n. 优先级 [prai'?riti]
process n. 程序, 进程
protected (关键字) 受保护的,私有的
provide v.规定(供应,准备,预防)
refer to v.引用
reference n. 参考(引用,涉及) -->reference variable 参量, 参考变量,引用变量
Reflection [java] 反射
script n.手写体,小型程序 [skript]
serialized vt.序列化,串行化 (serializable adj.)(deserialize反序列化,反串行化)
Socket [java] 网络套接字
stack n.堆栈(对应 heap 堆)
statement 程序语句; 语句 n. 陈述,指令
subclass n.子类 (supertype 父类)
switch (关键字) 选择语句。 n.开关,道岔
synchronized (关键字) 同步(锁)
Thread [java] 线程 [θred]
throw (关键字) throws (关键字) 抛出(异常)
transient (关键字) 瞬变;临时的(可序列化)
valid 正确的,有效的
variable n.变量 a.可变的
volatile (关键字) 不稳定的
while (关键字) 循环语句。 当...的时候 [hwail]
NO.2lunix 命令
一、注意事项
命令和参数之间必需用空格隔开,参数和参数之间也必需用空格隔开。
一行不能超过256个字符;大小写有区分。
二、特殊字符含义
文件名以“.”开头的都是隐藏文件/目录,只需在文件/目录名前加“.”就可隐藏它。
~/ 表示主目录。
./ 当前目录(一个点)。
../ 上一级目录(两个点)。
; 多个命令一起用。
> >> 输出重定向 。将一个命令的输出内容写入到一个文件里面。如果该文件存在, 就将该文件的内容覆盖;
如果不存在就先创建该文件, 然后再写入内容。
输出重定向,意思就是说,将原来屏幕输出变为文件输出,即将内容输到文件中。
< << 输入重定向。 本来命令是通过键盘得到输入的,但是用小于号,就能够使命令从文件中得到输入。
\ 表示未写完,回车换行再继续。
* 匹配零个或者多个字符。
? 匹配一个字符。
[] 匹配中括号里的内容[a-z][A-Z][0-9]。
! 事件。
$ 取环境变量的值。
| 管道。把前一命令的输出作为后一命令的输入,把几个命令连接起来。
|经常跟tee连用,tee 把内容保存到文档并显示出来。
三、通用后接命令符
-a 所有(all)。
-e 所有(every),比a更详细。
-f 取消保护。
-i 添加提示。
-p 强制执行。
-r 目录管理。
分屏显示的中途操作
空格<space> 继续打开下一屏;
回车<return> 继续打开下一行;
b 另外开上一屏;
f 另外开下一屏;
h 帮助;
q或Ctrl+C 退出;
/字符串 从上往下查找匹配的字符串;
?字符串 从下往上查找匹配的字符串;
n 继续查找。
四、退出命令
exit 退出; DOS内部命令 用于退出当前的命令处理器(COMMAND.COM) 恢复前一个命令处理器。
Ctrl+d 跟exit一样效果,表中止本次操作。
logout 当csh时可用来退出,其他shell不可用。
clear 清屏,清除(之前的内容并未删除,只是没看到,拉回上面可以看回)。
五、目录管理命令
pwd 显示当前所在目录,打印当前目录的绝对路径。
cd 进入某目录,DOS内部命令 显示或改变当前目录。
cd回车/cd ~ 都是回到自己的主目录。
cd . 当前目录(空格再加一个点)。
cd .. 回到上一级目录(空格再加两个点)。 cd ../.. 向上两级。
cd /user/s0807 从绝对路径去到某目录。
cd ~/s0807 直接进入主目录下的某目录(“cd ~"相当于主目录的路径的简写)。
ls 显示当前目录的所有目录和文件。
用法 ls [-aAbcCdeEfFghHilLmnopqrRstux1@] [file...]
ls /etc/ 显示某目录下的所有文件和目录,如etc目录下的。
ls -l (list)列表显示文件(默认按文件名排序),
显示文件的权限、硬链接数(即包含文件数,普通文件是1,目录1+)、用户、组名、大小、修改日期、文件名。
ls -t (time)按修改时间排序,显示目录和文件。
ls -lt 是“-l”和“-t”的组合,按时间顺序显示列表。
ls -F 显示文件类型,目录“/ ”结尾;可执行文件“*”结尾;文本文件(none),没有结尾。
ls -R 递归显示目录结构。即该目录下的文件和各个副目录下的文件都一一显示。
ls -a 显示所有文件,包括隐藏文件。
文件权限
r 读权限。对普通文件来说,是读取该文件的权限;对目录来说,是获得该目录下的文件信息。
w 写权限。对文件,是修改;对目录,是增删文件与子目录。
(注 删除没有写权限的文件可以用 rm -f ,这是为了操作方便,是人性化的设计)。
x 执行权限;对目录,是进入该目录
- 表示没有权限
形式 - rw- r-- r--
其中 第一个是文件类型(-表普通文件,d表目录,l表软链接文件)
第2~4个是属主,生成文件时登录的人,权限最高,用u表示
第5~7个是属组,系统管理员分配的同组的一个或几个人,用g表示
第8~10个是其他人,除属组外的人,用o表示
所有人,包括属主、属组及其他人,用a表示
chmod 更改权限;
用法 chmod [-fR] <绝对模式> 文件 ...
chmod [-fR] <符号模式列表> 文件 ...
其中 <符号模式列表> 是一个用逗号分隔的表 [ugoa]{+|-|=}[rwxXlstugo]
chmod u+rw 给用户加权限。同理,u-rw也可以减权限。
chmod u=rw 给用户赋权限。与加权限不一样,赋权限有覆盖的效果。
主要形式有如下几种
chmod u+rw chmod u=rw
chmod u+r, u+w chmod u+rw,g+w, o+r
chmod 777( 用数字的方式设置权限是最常用的)
数字表示权限时,各数位分别表示属主、属组及其他人;
其中,1是执行权(Execute),2是写权限(Write),4是读权限(Read),
具体权限相当于三种权限的数相加,如7=1+2+4,即拥有读写和执行权。
另外,临时文件/目录的权限为rwt,可写却不可删,关机后自动删除;建临时目录:chmod 777 目录名,再chmod +t 目录名。
id 显示用户有效的uid(用户字)和gid(组名)
用法 id [-ap] [user]
id 显示自己的。
id root 显示root的。
id -a root 显示用户所在组的所有组名(如root用户,是所有组的组员)
df 查看文件系统,查看数据区
用法 df [-F FSType] [-abeghklntVvZ] [-o FSType 特定选项] [目录 | 块设备 | 资源]
df -k 以kbytes显示文件大小的查看文件系统方式
六、显示文件内容
more 分屏显示文件的内容。
用法 more [-cdflrsuw] [-行] [+行号] [+/模式] [文件名 ...]。
显示7个信息:用户名 密码 用户id(uid) 组id(gid) 描述信息(一般为空) 用户主目录 login shell(登录shell)
cat 显示文件内容,不分屏(一般用在小文件,大文件显示不下);合并文件,仅在屏幕上合并,并不改变原文件。
用法 cat [ -usvtebn ] [-|文件] ...
tail 实时监控文件,一般用在日志文件,可以只看其中的几行。
用法 tail [+/-[n][lbc][f]] [文件]
tail [+/-[n][l][r|f]] [文件]
七、文件/目录的增删
echo 显示一行内容。
touch 如果文件/目录不存在,则创建新文件/目录;如果文件存在,那么就是更新该文件的最后访问时间,
用法 touch [-acm] [-r ref_file] 文件...
touch [-acm] [MMDDhhmm[yy]] 文件...
touch [-acm] [-t [[CC]YY]MMDDhhmm[.SS]] file...
mkdir 创建目录(必须有创建目录的权限)
用法 mkdir [-m 模式] [-p] dirname ...
mkdir dir1/dir2 在dir1下建dir2
mkdir dir13 dir4 dir5 连建多个
mkdir ~/games 用户主目录下建(默认在当前目录下创建)
mkdir -p dir6/dir7/dir8 强制创建dir8;若没有前面的目录,会自动创建dir6和dir7。
不用-p时,若没有dir6/dir7,则创建失败。
cp 复制文件/目录
cp 源文件 目标文件 复制文件;若已有文件则覆盖
cp -r 源目录 目标目录 复制目录;若已有目录则把源目录复制到目标目录下,
没有目标目录时,相当于完全复制源目录,只是文件名不同。
cp beans apple dir2 把beans、apple文件复制到dir2目录下
cp -i beans apple 增加是否覆盖的提示
mv 移动或重命名文件/目录
用法 mv [-f] [-i] f1 f2
mv [-f] [-i] f1 ... fn d1
mv [-f] [-i] d1 d2
mv 源文件名 目标文件名 若目标文件名还没有,则是源文件重命名为目标文件;若目标文件已存在,则源文件覆盖目标文件。
mv 源文件名 目标目录 移动文件
mv 源目录 目标目录 若目标目录不存在,则源目录重命名;若目标目录已存在,则源目录移动到目标目录下。
rm 删除文件/目录
用法 rm [-fiRr] 文件 ...
rm 文件名 删除文件。
rm -r 目录名 删除目录。
rm –f 文件 只要是该文件或者目录的拥有者,无论是否有权限删除,都可以用这个命令参数强行删除。
rm -rf * 删除所有文件及目录
rmdir 删除空目录。只可以删除空目录。
ln 创建硬链接或软链接,硬链接=同一文件的多个名字;软链接=快捷方式
用法 ln [-f] [-n] [-s] f1 [f2]
ln [-f] [-n] [-s] f1 ... fn d1
ln [-f] [-n] -s d1 d2
ln file1 file1.ln 创建硬链接。感觉是同一文件,删除一个,对另一个没有影响;须两个都删除才算删除。
ln -s file1 file1.sln 创建软链接。可跨系统操作,冲破操作权限;也是快捷方式。
八、时间显示
date 显示时间,精确到秒
用法 date [-u] mmddHHMM[[cc]yy][.SS]
date [-u] [+format]
date -a [-]sss[.fff]
cal 显示日历
cal 9 2008 显示2008年9月的日历; cal 显示当月的
用法 cal [ [月] 年 ]
九、帮助
man 帮助( format and display the on-line manual pages)
用法 man [-] [-adFlrt] [-M 路径] [-T 宏软件包] [-s 段] 名称 ...
man [-] [-adFlrt] [-M path] [-T macro-package] [-s section] name...
man [-M 路径] -k 关键字 ...
man [-M 路径] -f 文件 ...
awk 按一定格式输出(pattern scanning and processing language)
用法 awk [-Fc] [-f 源代码 | 'cmds'] [文件]
十、vi
底行模式 /? 命令模式 i a o 输入模式
vi 的使用方法
1、光标 h 左 j 下 k 上 l 右
set nu 显示行号(set nonu) 21 光标停在指定行
21G 第N行 (G到文件尾,1G到文件头) 如果要将光标移动到文件第一行,那么就按 1G
H 屏幕头
M 屏幕中间
L 屏幕底
^ 或 shift+6 行首
$ 或 shift+4 行尾
Ctrl+f 下翻
Ctrl+b 上翻
2、输入 (输入模式)
o 光标往下换一行
O (大写字母o)在光标所在行上插入一空行
i 在光标所在位置的前面插入字母
a 在光标所在位置的后面插入一个新字母
<Esc> 退出插入状态。
3、修改替换
r 替换一个字符
dd 删除行,剪切行 (5dd删除5行)
5,10d 删除 5 至 10 行(包括第 5行和第 10 行)
x 删除一个字符
dw 删除词,剪切词。 ( 3dw删除 3 单词)
cw 替换一个单词。 (cw 和 dw 的区别 cw 删除某一个单词后直接进入编辑模式,而dw删除词后仍处于命令模式)
cc 替换一行
C 替换从光标到行尾
yy 复制行 (用法同下的 Y ,见下行)
Y 将光标移动到要复制行位置,按yy。当你想粘贴的时候,请将光标移动到你想复制的位置的前一个位置,然后按 p
yw 复制词
p 当前行下粘贴
1,2co3 复制行1,2在行3之后
4,5m6 移动行4,5在行6之后
u 当你的前一个命令操作是一个误操作的时候,那么可以按一下 u键,即可复原。只能撤销一次
r file2 在光标所在处插入另一个文件
~ 将字母变成大写
J 可以将当前行与下一行连接起来
/字符串 从上往下找匹配的字符串
?字符串 从下往上找匹配的字符串
n 继续查找
1,$s/旧串/新串/g 替换全文(或者 %s/旧串/新串/g)
(1表示从第一行开始) 没有g则只替换一次,加g替换所有
3、存盘和退出
w 存盘
w newfile 存成新文件
wq 存盘再退出VI(或者ZZ或 X)
q! 强行退出不存盘
查看用户
users 显示在线用户(仅显示用户名)。
who 显示在线用户,但比users更详细,包括用户名、终端号、登录时间、IP地址。
who am i 仅显示自己,(但包括用户名、端口、登录时间、IP地址;信息量=who)。
whoami 也仅显示自己,但只有用户名(仅显示自己的有效的用户名)。
w 显示比who更多内容,还包括闲置时间、占CPU、平均占用CPU、执行命令。
用法 w [ -hlsuw ] [ 用户 ]
su 改变用户,需再输入密码。
用法 su [-] [ username [ arg ... ] ]
su - 相当于退出再重新登录。
查找
find 查找文件
用法 find [-H | -L] 路径列表 谓词列表
find / -name perl 从根目录开始查找名为perl的文件。
find . -mtime 10 -print 从当前目录查找距离现在10天时修改的文件,显示在屏幕上。
(注 “10”表示第10天的时候;如果是“+10”表示10天以外的范围;“-10”表示10天以内的范围。)
grep 文件中查找字符;有过滤功能,只列出想要的内容
用法 grep -hblcnsviw 模式 文件 . . .
如 grep abc /etc/passwd 在passwd文件下找abc字符
wc 统计
-l 统计行数; -w统计单词数; -c 统计字符数
如 grep wang /etc/passwd|wc -l 统计passwd文件含“wang”的行数
du 查看目录情况
如 du -sk * 不加-s会显示子目录,-k按千字节排序
用法 du [-a] [-d] [-h|-k] [-r] [-o|-s] [-H|-L] [文件...]
进程管理
ps 显示进程。
用法 ps [ -aAdeflcjLPyZ ] [ -o 格式 ] [ -t 项列表 ]
[ -u 用户列表 ] [ -U 用户列表 ] [ -G 组列表 ]
[ -p 进程列表 ] [ -g 程序组列表 ] [ -s 标识符列表 ] [ -z 区域列表 ]
ps 显示自己的进程。
ps -e 显示每个进程,包括空闲进程。
ps -f 显示详情。
ps -ef 组合-e和-f,所有进程的详情。
ps -U uidlist(用户列表) 具体查看某人的进程。
kill
pkill
sleep
jobs
用法 jobs [-l ]
fg %n
bg %n
stop %n 挂起(仅csh能用)
Ctrl+C
Ctrl+Z
网络链接
ping
usage ping host [timeout]
usage ping -s [-l | U] [adLnRrv] [-A addr_family] [-c traffic_class] [-g gateway [-g gateway ...]] [-F flow_label] [-I interval] [-i interface] [-P tos] [-p port] [-t ttl] host [data_size] [npackets]
ifconfig -a
/sbin/ifconfig 查看本机的IP地址
No.3:hashcode这个方法是用来鉴定2个对象是否相等的。 那你会说,不是还有equals这个方法吗? 不错,这2个方法都是用来判断2个对象是否相等的。但是他们是有区别的。 一般来讲,equals这个方法是给用户调用的,如果你想判断2个对象是否相等, 你可以重写equals方法,然后在代码中调用,就可以判断他们是否相等了。 简单来讲,equals方法主要是用来判断从表面上看或者从内容上看,2个对象是不是相等。 举个例子,有个学生类,属性只有姓名和性别,那么我们可以认为只要姓名和性别相等, 那么就说这2个对象是相等的。 NO.4 --面对对象 类与对象之间的关系(6种): 关联 Association:一个类受另一个类影响(实线) 聚合关联 Aggregation:弱'拥有'关系,A对象可以包含B对象,但B不是A的一部分(空心菱形+实线箭头)[DPE] (DPE 表示这句话来自《设计模式》) 组合关联 Composition:(也叫合成,组成)是一种强的‘拥有’关系,体现严格的部分和整体的关系, 部分和整体的生命周期一样[DPE](实心菱形+实线箭头) 组合图形的基数:表明这一端的类可以有几个实例,(一只鸟有两个翅膀)如果有无数个实例,则用n表示 关联关系、聚合关系也可以有基数 依赖 Dependency :一个类需要另外一个类(X需要Y,则X的修改Y也要跟着修改) (虚线箭头) 泛化(继承) (实心菱形+实线) 实现 (实心菱形+虚线 ) 面向对象的7大基本设计原则 程序设计:没有最好,只有最适合。寻找平衡点。 1. LSP(The Liskov Substitution Principle ,替换原则) 父类出现的地方,子类都可出现。 子类或实现类与父类都是可以互换的。 子类不能添加任何父类没有的附加约束 子类对象必须可以替换父类对象 2. OCP (The Open-Close Principle,开闭原则) 要关联抽象,不要关联具体,抽象可扩展。 扩展是开放的,更改是封闭的 3. SRP(The Single Responsibility Principle,单一职责原则) 依赖不同的具体类,不要将不相关的方法放到一个具体类中,然后具体类再关联。 一个类,应该仅有一个引起它变化的原因 当需求变化时,该变化会反映为类的职责的变化(如果有多个职责,引起变化的原因就会有多个) 4. ISP(The Interface Segregation Principle,接口隔离原则) 具体类不要实现无关接口中的方法,应使用具体类实现多个接口。 避免肥接口,以一个类实现多个接口,而各客户仅仅获知必须的接口 本质: 使用多个专门的接口比使用单一的接口好 一个类对另一个类的依赖性应当最小化 避免接口污染(Interface Pollution)(使用不必要的功能) 5. DIP(The Dependency Inversion Principle,依赖倒置原则) 高层依赖于抽象,底层继承/实现于抽象。 高层模块不应该依赖于低层模块,二者都应该依赖于抽象 细节应该依赖于抽象,而抽象不应该依赖于细节 针对接口编程,不是针对实现编程 6. CARP(Composite/Aggregate Reuse Principle,组合/聚合复用原则) 尽量使用组合/聚合,而不是使用继承来达到复用目的 继承的缺点:会带来不必要的方法 组合/聚合的解决方案 组合:部分的更改会影响整体的生命 ***:部分的更改对整体的影响不大 7. LoD(Law of Demeter,迪米特法则) 类间最少通信原则,采用中间类。 也称最少知识原则。一个对象或模块应该和其它对象和模块尽量少的通信 1. 对象 名词 对象: 类: 一类属性相同的对象 属性:是什么样 方法:能做什么(C 中叫作函数) 对象: 声明:Student s ; 这时我们只是说明s是一个能够指向Student类型的引用(相当于C++中的指针),并没有创建一个对象。 所以我们此时不能对s做任何操作。 初始化:s = new Student(); 向系统申请一块存储空间(地址空间),该地址空间保存的是一个Student类型的数据。 而s中保存的就是该地址空间的首地址。 变量:内存空间中一块具有固定长度的,用来保存数据的地址空间。(s也是一个变量) 一个对象可以有多个引用指向。 Student[] s = new Student[3] 只是相当于声明一个长度为 3 的Student类型的数组。 2.实例变量和局部变量 实例变量: 1、在一个类中,任何方法之外定义的变量; 2、从面向对象的思想来说我们又把实例变量看成一个类的属性。 3、实例变量在没有符初值时系统会自动帮我们做初始化: 整型数据初始化为 0,布尔型数据初始化为 false,对象类型初始化为 null。 实例变量的作用域在本类中完全有效,当被其他的类调用的时候也可能有效。 局部变量: 1、在方法内定义的变量叫局部变量。 2、局部变量使用前必须初始化,系统不会自动给局部变量做初始化。 3、局部变量的生命范围在他所在的代码块,在重合的作用域范围内不允许两个局部变量命名冲突。 注:局部变量与实例变量允许同名,在局部变量的作用域内,其优先级高于实例变量。 我们可以用 this.实例变量名 以区分局部变量。 3.在java中对面向对象(OO)的要求 1.对象是客观存在的,万物皆对象。 (注:看不见的对象并不表示该对象不存在,比如说事件); 2.简单性:采用面向对象方法可以使系统各部分各司其职各尽所能。 3.复用性:对象的功能越简单其可重用性越高。 4.弱耦合性:各司其职各尽所能。 5.高内聚性:一个对象独立完成一个功能的能力 6.类是一类事务的共性,是人类主观认识的一种抽象,是对象的模板。 面向过程与面向对象的对比 面向过程:先有算法,后有数据结构。先考虑怎么做。 面向对象:先有数据结构,后有算法。先考虑用什么做。 4. 构造方法 方法的声明(分为五个部分) 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 关键字也是个隐形参数,代表被构造对象的父类。 同样也必须在构造方法的第一行 对象和对象引用的区别 对象好比一台电视机,对象引用好比电视机遥控。对象引用 中存的是对象的地址。 多个对象引用中存放的是同一个地址,表示该对象被多个对象引用所引用。 5.面向对象的三大特性: 封装(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 成员(只要调用这个类的属性或方法都需创建一次); 递归地创建父类对象(先创建父类非静态成员,再调用父类构造方法); 顺序地创建本类非静态成员(包括属性和方法); 调用本类的构造方法(它可调用本类或父类的成员,也可调用本类的其他构造方法)。 创建完成了(更多详情参看下面:类加载的顺序) 6.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 两类。 不可以有静态属性和方法(final 的除外),因为 static 在加载类的时候创建,这时内部类还没被创建 如果在外部类的外部访问内部类,使用out.inner.*** 建立内部类对象时应注意: 在创建成员内部类的实例时,外部类的实例必须存在: 在外部类的内部可以直接使用inner s=new inner(); 因为外部类知道 inner 是哪个类。 而在外部类的外部,要生成一个内部类对象,需要通过外部类对象生成。 Outer.Inner in = new Outer().new Inner(); 相当于:Outer out = new Outer(); Outer.Inner in = out.new Inner(); 错误的定义方式:Outer.Inner in=new Outer.Inner()。 ② 局部内部类:在方法中定义的内部类称为局部内部类。 类似局部变量,不可加修饰符 public、protected 和 private,其范围为定义它的代码块。 可以访问外部类的所有成员,此外,还可以访问所在方法中的 final 类型的参数和变量。 在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。 要想使用局部内部类时需要生成对象,对象调用方法,在方法中才能调用其局部内部类。 局部内部类不能声明接口和枚举。 ③ 静态内部类:(也叫嵌套类) 静态内部类定义在类中,在任何方法外,用 static 定义。 静态内部类能直接访问外部类的静态成员; 不能直接访问外部类的实例成员,但可通过外部类的实例(new 对象)来访问。 静态内部类里面可以定义静态成员(其他内部类不可以)。 生成(new)一个静态内部类不需要外部类成员,这是静态内部类和成员内部类的区别。 静态内部类的对象可以直接生成: Outer.Inner in=new Outer.Inner(); 对比成员内部类:Outer.Inner in = Outer.new Inner(); 而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。 静态内部类不可用 private 来进行定义。例子: 对于两个类,拥有相同的方法: /*************************************************************************/ /*class People{void run();} interface Machine{void run();} 此时有一个robot类: class Robot extends People implement Machine. 此时run()不可直接实现。*/ interface Machine{ void run();} class Person{ void run(){System.out.println("run");}} class Robot extends Person{ private class MachineHeart implements Machine{ public void run(){System.out.println("heart run");} } public void run(){System.out.println("Robot run");} Machine getMachine(){return new MachineHeart();} } class Test{ public static void main(String[] args){ Robot robot=new Robot(); Machine m=robot.getMachine(); m.run(); robot.run(); }} /*************************************************************************/ 注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。 这是唯一一种必须使用内部类的情况。 用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。 ④ 匿名内部类: 【1】匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。 【2】不同的是他是用一种隐含的方式实现一个接口或继承一个类,而且他只需要一个对象 【3】在继承这个类时,根本就没有打算添加任何方法。 【4】匿名内部类大部分情况都是为了实现接口的回调。 注:匿名内部类一定是在 new 的后面 其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。 因其为局部内部类,那么局部内部类的所有限制都对其生效。 匿名内部类是唯一一种无构造方法类。 注:这是因为构造器的名字必须和类名相同,而匿名内部类没有类名。 匿名内部类在编译的时候由系统自动起名Out$1.class。 因匿名内部类无构造方法,所以其使用范围非常的有限。 结尾需加上分号。 匿名内部类的例子: /*************************************************************************/ public class test{ public static void main(String[] args){ B.print(new A(){ public void getConnection(){ System.out.println("Connection....");} }); }} interface A{ void getConnection();} class B{ public static void print(A a){ a.getConnection();} } /*************************************************************************/ 枚举和接口可以在类的内部定义,但不能在方法内部定义。 接口里面还可以定义多重接口和类。 类放在什么位置,就相当于什么成员。 内部类的用途: 封装类型:把标准公开,把标准的实现者作为内部类隐藏起来, 强制要求使用者通过标准访问标准的实现者,从而强制做到弱耦合! 直接访问外部类的成员 配合接口,实现多继承,当父类和接口方法定义发生冲突的时候,就必须借助内部类来区分 模板回调 从内部类继承: 由于直接构造实例内部类时,JVM会自动使内部类实例引用它的外部类实例。 但如果下面Sample类通过以下方式构造对象时:Sample s = new Sample(); JVM无法决定Sample实例引用哪个Outer实例,为了避免这种错误的发生,在编译阶段,java编译器会要求Sample类的构造方法必须通过参数传递一个Outer实例的引用,然后在构造方法中调用super语句来建立Sample实例与Outer实例的关联关系。 /*************************************************************************/ public class Sample extends Outer.Inner{ //public Sample(){} //编译错误 public Sample(Outer o){ o.super(); } public static void main(String args[]){ Outer outer1=new Outer(1); Outer outer2=new Outer(2); Outer.Inner in=outer1.new Inner(); in.print(); Sample s1=new Sample(outer1); Sample s2=new Sample(outer2); s1.print(); //打印a=1 s2.print(); //打印a=2 }} /*************************************************************************/ 内部接口: 在一个类中也可以定义内部接口 在接口中可以定义静态内部类,此时静态内部类位于接口的命名空间中。 在接口中还可以定义接口,这种接口默认也是public static 的,如Map.Entry就是这种接口 第八章 Collection FrameWork 《集合框架》 ((Iterator接口 ←- Iterable接口 )) ← Collection接口 ↑ ┌--------------------------------┬---------------┐ Set接口 List接口 Queue接口 ↑ ↑ ↑ ┌----------┐ ┌-----------+---------┐ ┌-----------┐ HashSet SortedSet接口 Vector ArrayList LinkedList PriorityQueue ↑ TreeSet Map接口 ↑ ┌----------┐ HashMap SortedMap接口 ↑ TreeMap 各接口的主要方法: Iterable: +iterator() Iterator: +hasNext() +next() +remove() Collection: +add() +remove() +clear() +isEmpty() +size() +contains() List: +get() +set() +remove() Queue: +element() +offer() +peek() +poll() Set: SortedSet: +comparator() +first() +last() +headSet() +tailSet() Map: +clear() +containsKey() +containsValue() +get() +keySet() +isEmpty() +remove() +put()会替换重复键 +size() +values() SortedMap: +comparator() +firstKey() +lastKey() +headMap() +tailMap() 一、集合(容器,持有对象):是一个用于管理其他多个对象的对象,且只能保存对象的引用,不是放对象。 1、Collection: 集合中每一个元素为一个对象,这个接口将这些对象组织在一起,形成一维结构。 2、List: 有序、可重复。 ArrayList: 数组。查询快,增删慢。(List是链表) Vector: 线程安全,但效率很差(现实中基本不用) 3、Set: 无序,且不可重复(不是意义上的重复)。(正好与List 对应) HashSet: 用 hashCode() 加 equals() 比较是否重复 SortedSet: 会按照数字将元素排列,为“可排序集合”默认升序。 TreeSet: 按二叉树排序(效率非常高); 按Comparable接口的 compareTo() 比较是否重复 4、Map: 其中每一个元素都是一个键值对( Key-Value)。键不能重复。可有一个空键。 SortedMap: 根据 key 值排序的 Map。 HashMap: 用 hashCode() 加 equals() 比较是否重复 5、Queue: 队列:先进先出。 PriorityQueue: 优先队列:元素按照其自然顺序进行排序,或者根据构造队列时提供的 Comparator 进行排序 注意:在“集合框架”中,Map 和Collection 没有任何亲缘关系。 Map的典型应用是访问按关键字存储的值。它支持一系列集合操作,但操作的是键-值对,而不是独立的元素 因此 Map 需要支持 get() 和 put() 的基本操作,而 Set 不需要。 《常用集合列表》 ' 存放元素 存放顺序 元素可否重复 遍历方式 排序方式 各自实现类 List Object 有序 可 迭代 (2) ArrayList, TreeSet Set Object 无序 不可 迭代 SortedSet HashSet SortedSet Object 无序 不可 迭代 已排序 TreeSet Map (1) Key无序 Key不可,value可 对Key迭代 SortedMap HashMap SortedMap (1) 无序,有排序 Key不可,value可 对Key迭代 已对键值排序 TreeMap (1)Object(key)—Object(value); (2)Collections.sort(); 注:以上有序的意思是指输出的顺序与输入元素的顺序一致 HashSet、HashMap通过hashCode(),equals()来判断重复元素 在java中指定排序规则的方式只有两种:1、实现java.util包下的Comparator接口 2、实现java.lang包下的Comparable接口 二、迭代器:Iterator 1、使用Iterator接口方法,您可以从头至尾遍历集合,并安全的从底层Collection中除去元素 2、remove() 由底层集合有选择的支持。底层集合支持并调用该方法时,最近一次next()返回的元素将被删 3、Collection 接口的iterator() 方法返回一个Iterator 4、Iterator中的hasNext()用于判断元素右边是否有数据,返回True则有。然后就可以调用next()动作。 5、Iterator中的next()方法会将游标移到下一个元素,并返回它所跨过的元素。(通常这样遍历集合) 6、用于常规Collection 的Iterator 接口代码如下: /*迭代遍历*/ List l = new ArrayList(); Iterator it = l.iterator(); while(it.hasNext()){ Object obj = it.next(); System.out.println(obj); } 注:工具类是指所有的方法都是公开静态方法的类。 Java.util.collections就是一个工具类; 三、对集合的排序 1、我们可以用Java.util.collections中的sort(List l)方法对指定的List集合进行排序; 但是如果List中存放的是自定义对象时,这个方法就行不通了,必须实现Comparable接口并且指定排序规则。 这里我们再来看一下sort(List l)方法的内部实现; /**********************************************************/ class Collections2{ public static void sort(List l){ for(int i=0;i<l.size()-1;i++){ for(int j=i+1;j<l.size();j++){ Object o1 = l.get(i); Object o2 = l.get(j); Comparable c1 = (Comparable)o1; Comparable c2 = (Comparable)o2; if(c1.compareTo(c2)>0){ Collections.swap(l,i,j); }}}}} //其实用的算法就是个冒泡排序。 /******************************************************/ 2、实现Java.lang.Comparable接口,其实就是实现他的 public int compareTo(Object obj)方法; 比较此对象与指定对象的顺序。如果该对象小于、等于或大于指定对象,则分别返回负整数、零或正整数。 其规则是当前对象与obj 对象进行比较,其返回一个 int 值,系统根据此值来进行排序。 如当前对象 > obj,则返回值>0; 如当前对象 = obj,则返回值=0; 如当前对象 < obj,则返回值<0。 注意:String类型已经实现了这个接口,所以可以直接排序; /******************************************************/ class Student implements Comparable{ private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } public int compareTo(Object obj) { Student s = (Student)obj; return s.age-this.age; }} /******************************************************/ 四、ArrayList和LinkedList集合 1、ArrayList 底层是object 数组,所以ArrayList 具有数组的查询速度快的优点以及增删速度慢的缺点。 Vector 底层实现也是数组,但他是一个线程安全的重量级组件。 2、而在LinkedList 的底层是一种双向循环链表。 在此链表上每一个数据节点都由三部分组成: 前指针(指向前面的节点的位置)、 数据、 后指针(指向后面的节点的位置)。 最后一个节点的后指针指向第一个节点的前指针,形成一个循环。 3、双向循环链表的查询效率低但是增删效率高。所以LinkedList 具有查询效率低但增删效率高的特点。 4、ArrayList 和LinkedList 在用法上没有区别,但是在功能上还是有区别的。 LinkedList 经常用在增删操作较多而查询操作很少的情况下:队列和堆栈。 队列:先进先出的数据结构。 堆栈:后进先出的数据结构。 (堆栈就是一种只有增删没有查询的数据结构) 注意:使用堆栈的时候一定不能提供方法让不是最后一个元素的元素获得出栈的机会。 LinkedList 提供以下方法:(ArrayList 无此类方法) addFirst(); +removeFirst(); +addLast(); +removeLast(); 在堆栈中,push 为入栈操作,pop 为出栈操作。 Push 用addFirst();pop 用removeFirst(),实现后进先出。 用isEmpty()--其父类的方法,来判断栈是否为空。 在队列中,put 为入队列操作,get 为出队列操作。 Put 用addFirst(),get 用removeLast()实现队列。 List 接口的实现类 Vector 与ArrayList 相似,区别是Vector 是重量级组件,消耗的资源较多。 结论:在考虑并发的情况下用Vector(保证线程的安全)。 在不考虑并发的情况下用ArrayList(不能保证线程的安全)。 5、面试经验(知识点): java.util.stack(stack 即为堆栈)的父类为Vector。可是stack 的父类是最不应该为Vector 的。 因为Vector的底层是数组,且Vector有get方法(意味着它可能访问任意位置的元素,很不安全)。 对于堆栈和队列只能用push 类和get 类。(这是早期的某个java编写工程师的失误造成) Stack 类以后不要轻易使用。实现堆栈一定要用LinkedList。 (在JAVA1.5 中,collection 有queue 来实现队列。) 五、HashSet集合 1、HashSet是无序的,没有下标这个概念。HashSet集合中元素不可重复(元素的内容不可重复); 2、HashSet 底层用的也是数组。 3、HashSet如何保证元素不重复?Hash算法和equals方法。 当向数组中利用add(Object obj)添加对象的时候,系统先找对象的hashCode: int hc=obj.hashCode(); 返回的hashCode 为整数值。 int I=hc%n;(n 为数组的长度),取得余数后,利用余数向数组中相应的位置添加数据,以n 为6 为例, 如果I=0则放在数组a[0]位置,如果I=1则放在数组a[1]位置。 如果equals()返回true,则说明数据重复。如果equals()返回false,则再找其他的位置进行比较。 这样的机制就导致两个相同的对象有可能重复地添加到数组中,因为他们的hashCode 不同。 如果我们能够使两个相同的对象具有相同hashcode,才能在equals()返回为真。 在实例中,定义student 对象时覆盖它的hashcode。 因为String类会自动覆盖,所以比较String 类的对象时,不会出现相同的string 对象的情况。 现在,在大部分的JDK 中,都已经要求覆盖了hashCode。 结论:如将自定义类用hashSet 来添加对象,一定要覆盖hashcode()和equals(), 覆盖的原则是保证当两个对象hashcode 返回相同的整数,而且equals()返回值为True。 如果偷懒,直接将hashCode方法的返回值设为常量;虽然结果相同,但会多次地调用equals(),影响效率。 我们要保证相同对象的返回的hashCode 一定相同,也要保证不相同的对象的hashCode 尽可能不同 (因为数组的边界性,hashCode 还是有极微几率相同的)。 六、TreeSet集合 1、TreeSet是SortedSet的实现类TreeSet通过实现Comparable接口的compareTo来实现元素不重复。 2、TreeSet由于每次插入元素时都会进行一次排序,因此效率不高。 3、java.lang.ClassCastException是类型转换异常。 4、在我们给一个类用CompareTo()实现排序规则时 5、从集合中以有序的方式抽取元素时,可用TreeSet,添加到TreeSet的元素必须是可排序的。 “集合框架”添加对Comparable 元素的支持。 一般说来,先把元素添加到HashSet,再把集合转换为TreeSet 来进行有序遍历会更快。 七、Map 1、HashMap集合 (1)HashMap就是用hash算法来实现的Map (2)在实际开发中一般不会用自定义的类型作为Map的Key。做Key的无非是八中封装类。 (3)HashMap的三组操作: 【1】改变操作,允许从映射中添加和除去键-值对。键和值都可以为null。 不能把Map作为一个键或值添加给自身。 –Object put(Object key, Object value) –Object remove(Object key) –void clear() 【2】查询操作允许您检查映射内容: –Object get(Object key) –intsize() –boolean isEmpty() 【3】最后一组方法允许您把键或值的组作为集合来处理。 –public Set KeySet(); –public Collection values() (4)HashMap和HashTable的区别等同于ArrayList和Vector的区别。 只不过HashTable中的Key和Value不能为空,而HashMap可以。 (5)HashMap底层也是用数组,HashSet底层实际上也是HashMap,HashSet类中有HashMap属性(查API)。 HashSet 实际上为(key.null)类型的HashMap。有key 值而没有value 值。 2、HashMap 类和TreeMap 类 •集合框架提供两种常规Map 实现:HashMap和TreeMap。 •在Map 中插入、删除和定位元素,HashMap 是最好选择。 •如果要按顺序遍历键,那么TreeMap 会更好。 •根据集合大小,先把元素添加到HashMap,再把这种映射转换成一个用于有序键遍历的TreeMap 可能更快。 •使用HashMap 要求添加的键类明确定义了hashCode() 实现。 •有了TreeMap 实现,添加到映射的元素一定是可排序的 •HashMap和TreeMap 都实现Cloneable 接口。 NO.5 数值保存方式: 正数= 二进制 负数= 补码 补码= 反码 +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; 这就会报错 关键字列表: 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 :这两个已经削去意义,但同样不能用作变量名。
Map
将一个或多个键映射到指定值,则返回
true
isEmpty()
如果
Map
不包含键
-
值映射,则返回
true
size()
返回
Map
中的键
-
值映射的数目