API文档注释写法
实例
:
package apidoc
;
public class APIDocDemo {
public static final String INFO
= "hello";
public String
sayHello(String name
) {
return "你好!"+name
;
}
}
--------String 字符串的API--------
JVM对String有一个优化措施,即:常量池java推荐我们使用"字面量"形式创建字符串对象,因为当我们这样做时虚拟机会首先检查常量池中是否有创建过该内容的字符串对象,若有,则直接重用对象。这样做可以减少内存中出现大量内容一样的字符串对象而带来的资源消耗等问题。频繁修改字符串代码的性能损耗(GC循环回收释放)
char charAt(int index)
返回当前字符串中给定位置处对应的字符
实例:
String str
= "thinking in java";
char c
= str
.charAt(9);
System
.out
.println(c
);
int length()
该方法返回当前字符串的长度
(字符个数
)
实例:
String str
= "我爱java";
System
.out
.println(str
.length());
int indexOf(String str)
查找给定字符串在当前字符串中的位置(首字母出现的位置
, 第一次出现的位置。
若当前字符串不包含该内容则返回值为
-1
实例:
String str
= "thinking in java";
int index
= str
.indexOf("in");
System
.out
.println(index
);
String substring(int start,int end)
截取当前字符串中指定范围内的内容
注
:在java API当中通常使用两个数字表示范围时,
都是
"含头不含尾"的
实例:
String str
= "www.tedu.cn";
String sub
= str
.substring(4, 8);
System
.out
.println(sub
);
sub
= str
.substring(4);
System
.out
.println(sub
);
boolean startsWith(String str) 和 boolean endsWith(String str)
判断字符串是否是以给定字符串
(前缀、后缀
)开始或结尾的
实例:
String str
= "thinking in java";
boolean starts
= str
.startsWith("thin");
System
.out
.println(starts
);
boolean ends
= str
.endsWith("ava");
System
.out
.println(ends
);
String toUpperCase() 和 String toLowerCase()
将当前字符串中的英文部分转换为全大写或全小写
实例:
String str
= "LOVEJava";
String upper
= str
.toUpperCase();
System
.out
.println(upper
);
String lower
= str
.toLowerCase();
System
.out
.println(lower
);
String trim()
去除当前字符串两边的空白字符
,字符串中间存在空格无法去除
实例:
String str
= " hello ";
String trim
= str
.trim();
System
.out
.println(str
);
System
.out
.println(trim
);
static String valueOf()
该方法用若干的重载,参数囊括基本类型及引用类型。
但是方法的作用是同样的,将给定的内容转换为字符串形式。比较常用的是将基本类型转换为字符串。
实例:
int a
= 1234;
String str
= String
.valueOf(a
);
System
.out
.println(str
);
str
= a
+"";
System
.out
.println(str
);
double d
= 123.123;
str
= String
.valueOf(d
);
System
.out
.println(str
);
String支持正则表达式的方法一:boolean matches(String regex)
使用给定的正则表达式验证当前字符串是否满足各式要求。
满足则返回
true,不满足则返回
false
需要注意
!!!!!
给定的正则表达式,无论是否添加了边界匹配符
(^....$
)
都是做全匹配验证。
实例:
String mail
= "fancq@tedu.cn";
\W
+@
(\W
[^_
])+(\\
.[a
-zA
-Z
]+)+
String regex
= "[a-zA-Z0-9_]+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)+";
boolean match
= mail
.matches(regex
);
if(match
) {
System
.out
.println("是邮箱");
}else {
System
.out
.println("不是邮箱");
}
String支持正则表达式方法二:String[] split(String regex)
将当前字符串按照满足正则表达式的部分进行拆分,将
拆分后的内容以String数组形式返回。
实例:
String str
= "abc123def456ghi";
String
[] array
= str
.split("[0-9]+");
System
.out
.println(array
.length
);
System
.out
.println(Arrays
.toString(array
));
str
= "1.2.3.4.5.6.7.8........";
array
= str
.split("\\.");
System
.out
.println(array
.length
);
System
.out
.println(Arrays
.toString(array
));
String image
= "1.jpg";
array
= image
.split("\\.");
image
= System
.currentTimeMillis()+"."+array
[1];
System
.out
.println(image
);
String支持正则表达式方法三:String replaceAll(String regex,String str)
将当前字符串中满足正则表达式的部分替换为给定内容
实例:
String str
= "abc123def456ghi";
str
= str
.replaceAll("[0-9]+", "#NUMBER#");
System
.out
.println(str
);
String regex
= "(wqnmlgb|sb|nc|mdzz|cnm|djb)";
String message
= "wqnmlgb!你个sb!你怎么这么的nc!cnm!你就是一个djb!";
message
= message
.replaceAll(regex
, "***");
System
.out
.println(message
);
StringBuilder
* 由于String的设计不适合频繁修改,对此java提供了一个
* 用于编辑字符串内容的类
:StringBuilder
* StringBuilder内部维护了一个可变的字符数组,不会每次
* 修改都来创建新对象,从而降低资源开销,提高执行效率。
* 其提供了方便编辑字符串内容的相关方法,包含
:
* 增,删,改,插等常见操作。
实例:
String str
= "好好学习java";
StringBuilder builder
= new StringBuilder(str
);
builder
.append(",为了找个好工作!");
String s
= builder
.toString();
System
.out
.println(s
);
builder
.replace(9, 16, "就是为了改变世界");
System
.out
.println(builder
);
builder
.delete(0, 8);
builder
.deleteCharAt(5);
System
.out
.println(builder
);
builder
.insert(0, "活着");
System
.out
.println(builder
);
实例:
public void StrBuilder() {
StringBuilder builder
=new StringBuilder("好好学习!");
builder
.append("天天向上!");
builder
.deleteCharAt(5);
builder
.replace(0, 4, "童话里的故事都是骗人的");
builder
.insert(10,",癞蛤蟆想吃天鹅肉");
System
.out
.println(builder
.toString());
}
* StringBuilder修改字符串内容的性能
实例:
StringBuilder builder
= new StringBuilder("a");
for(int i
=0;i
<10000000;i
++) {
builder
.append("a");
}
System
.out
.println("执行完毕!");
--------包装类API--------
Byte Short Integer Long Float Double Char Boolean
* 由于java中
8个基本类型不能直接参与面向
* 对象的开发
(不具有面向对象对应特性
)。
* 因此java为这
8个基本类型分别提供了对应
* 的引用类型,我们称它们为
:包装类
Integer i1
= Integer
.valueOf(1);
Double d1
= Double
.valueOf(1.0);
int d
= i1
.intValue();
double dou
= i1
.doubleValue();
int max
= Integer
.MAX_VALUE
;
int min
= Integer
.MIN_VALUE
;
byte bmax
= Byte
.MAX_VALUE
;
byte bmin
= Byte
.MIN_VALUE
;
* JDK1
.5推出时,推出了一个新的特性
:自动拆装箱。
* 该特性是编译器认可,而非虚拟机。编译器在编译源代码时
* 发现基本类型和引用类型相互赋值时,会自动添加代码补全
* 它们之间的转换操作。
int d
= 123;
Integer in
= d
;
d
= in
;
* 包装类都支持一个静态方法:
parseXXX(String str
)
* 该方法的作用是可以将字符串转换为对应的基本类型,但是
* 前提是该字符串的内容正确描述了基本类型可以保存的值。
String str
= "123";
int d
= Integer
.parseInt(str
);
System
.out
.println(d
);
double dou
= Double
.parseDouble(str
);
System
.out
.println(dou
);
* Byte、Short、Integer、Long、 包装类提供了一个进制转换的方法:
* public static int parseInt(String s
,int radix
)
* s
- 包含要解析的整数表示形式的 String
* radix
- 解析 s 时使用的基数
(进制
)。
public void parse7(){
String str
="123";
int num
=Integer
.parseInt(str
,7);
long numl
=Long
.parseLong(str
, 7);
System
.out
.println(num
);
System
.out
.println(numl
);
}
--------File文件操作相关API --------
File
* 使用File创建一个文件
* 在当前目录下创建名为
:test
.txt的文件
File file
= new File("./test.txt");
* boolean exists()
* 判断当前File表示的文件或目录是否已经存在
* 创建该文件时需要注意,创建的文件所在的目录必须存在,
* 否则会抛出异常。
file
.createNewFile();
'./': 表示当前项目工程根目录;
' /': 表示磁盘根目录
* 删除一个文件
* 将当前项目目录下的test
.txt文件删除在相对路径中,
"./"是可以忽略不写的,
* 默认就是从当前目录
(工程根目录
)开始的。
file
.delete();
* 在当前目录下创建一个名为demo的目录
创建目录:File dir
= new File("demo");
dir
.mkdir();
* 将当前目录下的demo目录删除
* delete方法在删除目录时要求该目录必须是一个空目录。
* 在当前目录下创建a
/b
/c
/d
/e
/f目录
File dir
= new File("a/b/c/d/e/f");
dir
.mkdirs();
删除目录:dir
.delete();
递归方法:
public static void delete(File f
) {
if(f
.isDirectory()) {
File
[] subs
= f
.listFiles();
for(int i
=0;i
<subs
.length
;i
++) {
File sub
= subs
[i
];
delete(sub
);
}
}
f
.delete();
}
public static void delete(File f
) {
if(f
.isDirectory()) {
File
[] sub
=f
.listFiles();
for (File file
: sub
) {
delete(file
);
}
}
f
.delete();
System
.out
.println("删除成功!");
}
* java
.io
.File
* File用来表示文件系统中的一个文件或目录
* 使用File可以
:
* 1:访问其表示的文件或目录的属性信息
(名字,大小等信息
)
* 2:创建或删除文件及目录
* 3:访问一个目录中的子项
* 但是File不能访问文件数据。
* 访问当前项目目录下的demo
.txt文件
*
* 相对路径的优势时可以跨平台跨环境,但是相对
* 的路径要根据实际运行环境而定。
* 在eclipse中运行java程序时,eclipse指定的
* "当前目录./"是当前程序所在的项目目录。
* 这里是JSD1808_SE这个目录。
File file
= new File("./demo.txt");
String name
= file
.getName();
long len
= file
.length();
boolean cr
= file
.canRead();
boolean cw
= file
.canWrite();
boolean ih
= file
.isHidden();
* 获取一个目录中的所有子项
* boolean isFile() 判断是否为文件
* boolean isDirectory() 判断是否为目录
* File
[] listFiles() 获取当前文件夹下的所有子文件。
if(dir
.isDirectory()) {
File
[] subs
= dir
.listFiles();
for(int i
=0;i
<subs
.length
;i
++) {
System
.out
.println(subs
[i
].getName());
}
}
* 重载的ListFiles方法,允许我们传入一个文件过滤器然后将目录中满足过滤器要求的子项返回。
public static void main(String
[] args
) {
File dir
= new File(".");
FileFilter filter
= new FileFilter() {
public boolean accept(File file
) {
String name
= file
.getName();
System
.out
.println("正在过滤:"+name
);
return name
.startsWith(".");
}
};
File
[] subs
= dir
.listFiles(filter
);
System
.out
.println(subs
.length
);
for(int i
=0;i
<subs
.length
;i
++) {
System
.out
.println(subs
[i
].getName());
}
}
RandomAccessFile
* 读取文件数据
RandomAccessFile raf
= new RandomAccessFile("raf.dat","r");
int d
= raf
.read();
* java
.io
.RandomAccessFile
* 专门用来读写文件数据的API,RAF基于指针对文件数据读写。
* 可以移动指针读写任意位置,所以可以灵活的对文件数据进行
* 编辑工作。
* 创建RAF时有两种常见模式
:
* r
:只读模式
* rw
:读写模式
* 向当前目录中的文件raf
.dat中写入一个字节
* 创建RandomAccessFile时常用的构造方法:
* RandomAccessFile(String path
,String mode
)
* RandomAccessFile(File file
,String mode
)
* mode
:模式,可以用
"rw","r"
* 注意,如果是只读模式时,文件不存在时会抛出异
* 常,若读写模式,则会在不存在时自动将该文件创
* 建出来
RandomAccessFile raf
= new RandomAccessFile("raf.dat","rw");
* long getFilePointer()
* 获取当前RAF的指针位置
* void seek(long pos
)
* 移动指针到指定位置
raf
.seek(0);
* RAF也提供了读取基本类型数据的方法
* int readInt()
* 连续读取
4字节并还原
int值。若在读取
4个字节的过程
* 中发现读取到文件末尾,则直接抛出异常
:
* EOFException EOF
:end of file
* 注
:这个方法并不会以返回
-1表示文件末尾,而是直接
* 抛异常,原因在于这里是真实读取
4字节的
int值,那么
* 在读取的数据中是可能读取到
int型
-1的,所以就不能
* 再用
int型
-1表示文件末尾了。
实例:
int d
= raf
.readInt();
long l
= raf
.readLong();
double dou
= raf
.readDouble();
raf
.writeInt(12);
raf
.writeLong(456);
raf
.writeDouble(3.14);
* 提高每次读写的数据量,减少实际发生的读写次数,可以
* 提高读写效率。
* 单字节读写的模式,一般称为:随机读写
* 一组一组字节读写的模式一般称为
:块读写
* RandomAccessFile提供了块读写的方法
:
* int read(byte[] data
)
* 一次性读取给定字节数组总长度的字节量并存入到
* 该数组中,返回值为实际读取到的字节量长度,若返回
* 值为
-1.则表示文件末尾
(本次没有读取到任何字节
)
* void write(byte[] data
)
* 一次性将给定的字节数组中所有字节写出
* void write(byte[] data
,int index
,int len
)
* 将给定字节数组从下标index处开始的连续len个字节
* 一次性写出
实例
:
RandomAccessFile src
= new RandomAccessFile("movie.mp4","r");
RandomAccessFile desc
= new RandomAccessFile("movie_cp.mp4","rw");
byte[] data
= new byte[1024*10];
int len
= -1;
long start
= System
.currentTimeMillis();
while((len
= src
.read(data
))!=-1) {
desc
.write(data
,0,len
);
}
long end
= System
.currentTimeMillis();
System
.out
.println("复制完毕!耗时:"+(end
-start
)+"ms");
src
.close();
desc
.close();
* 读取一个字符
* 问题:应当读取几个字节
?
* 除非了解该字符集编码规则。否则无法确定应当
* 读取多少个字节。
* RAF也有length方法,获取其读写的文件的长度
实例:
RandomAccessFile raf
= new RandomAccessFile("raf.txt","r");
byte[] data
= new byte[(int)raf
.length()];
raf
.read(data
);
String str
= new String(data
,"UTF-8");
System
.out
.println(str
);
raf
.close();
*使用RAF写出字符串
* String提供了将字符串转换为字节的方法
* byte[] getBytes():按照系统默认字符集转换
*
* byte[] getBytes(String charset
)
* 按照指定的字符集将字符串转换为字节,常见的
* 字符集
:
* GBK
:国标编码,英文
1字节,中文
2字节
* UTF
-8:对unicode进行编码的字符集,也成为万国码
* 其中英文
1字节,中文
3字节,其他国家文字
* 占用不等的字节量
实例:
RandomAccessFile raf
= new RandomAccessFile("raf.txt","rw");
String str
= "我可以接受你的所有,所有小脾气.";
byte[] data
= str
.getBytes("UTF-8");
raf
.write(data
);
str
= "我可以带你去吃很多,很多好东西.";
data
= str
.getBytes("UTF-8");
raf
.write(data
);
System
.out
.println("写出完毕!");
raf
.close();
--------文件IO流操作API--------
文件流
FileInputStream与FileOutputStream
* 文件流是一对低级流,是用来读写文件数据的流。
* 它们与RandomAccessFile都是用来读写文件数据的,但是
* 底层实际的读写方式不同。
* 文件流读取数据
实例:
FileInputStream fis
= new FileInputStream("fos.txt");
byte[] data
= new byte[100];
int len
= fis
.read(data
);
String str
= new String(data
,0,len
,"UTF-8");
System
.out
.println(str
);
fis
.close();
* 向文件中写入数据
* 文件流创建时,有两种写模式
:
* 1:覆盖写模式,即如果该文件已经存在,则会先将
* 文件数据清除。然后通过该流写入的数据做为文件数据。
* 2:追加写模式,在构造方法中再传入一个
boolean值
* 参数,若该值为
true,则是追加模式。那么若文件
* 存在,则原数据保留,通过该流写入的数据会被追加到文件末尾。
实例:
FileOutputStream fos
= new FileOutputStream("fos.txt",true);
String str
= "听我说,啊啊啊啊啊。";
byte[] data
= str
.getBytes("UTF-8");
fos
.write(data
);
System
.out
.println("写出完毕!");
fos
.close();
BufferedOutputStream
*使用缓冲输出流写出字符串时的缓冲区问题
* void flush()
* 缓冲流的flush方法会强制将缓冲区中已经缓存的
* 数据一次性写出。
* 频繁调用flush会降低写效率,但是可以保证写出
* 数据的即时性。结合实际需求使用该方法。
实例:
FileOutputStream fos
= new FileOutputStream("bos.txt");
BufferedOutputStream bos
= new BufferedOutputStream(fos
);
bos
.write("丝瓜鞋,一起骂,噢!".getBytes("UTF-8"));
bos
.flush();
System
.out
.println("写出完毕!");
bos
.close();
public static void buffReadWrite() throws IOException
{
FileOutputStream fos
=new FileOutputStream("fos.txt",true);
BufferedOutputStream bos
=new BufferedOutputStream(fos
);
bos
.write("世界等一等,一曲相思!".getBytes("UTF-8"));
bos
.flush();
System
.out
.println("写入成功!");
bos
.close();
FileInputStream fis
=new FileInputStream("fos.txt");
BufferedInputStream bis
=new BufferedInputStream(fis
);
byte[] data
=new byte[1024];
while(bis
.read(data
) != -1) {
String str
=new String(data
,"UTF-8");
System
.out
.println(str
);
}
bis
.close();
}
BufferedInputStream
*使用缓冲流提高读写效率
* 缓冲流是一对高级流,使用它们读写数据时,无论我们的读写
* 方式是单字节读写还是块读写,它都能提高读写效率。
* 在流链接中搭配不同的高级流可以简化我们对数据的读写操作
* 所谓流链接
:使用高级流链接其他流,最终链接在低级流上,
* 这样的串联操作可以对低级流上的数据做一系列的加工处理
* 工作。
实例:
FileInputStream fis
= new FileInputStream("music.mp3");
BufferedInputStream bis
= new BufferedInputStream(fis
);
FileOutputStream fos
= new FileOutputStream("music_cp3.mp3");
BufferedOutputStream bos
= new BufferedOutputStream(fos
);
int d
= -1;
while((d
= bis
.read())!=-1) {
bos
.write(d
);
}
System
.out
.println("复制完毕!");
bis
.close();
bos
.close();
ObjectOutputStream && ObjectInputStream
* 对象流
* 对象流是一对常见的高级流,作用是可以方便我们读写任何java对象。
*
* 对象输出流
:可以将java对象转换为一组字节后写出
.
*
* 对象输入流
:可以将一组字节读入并转换为对应的对象
,
* 读取的字节必须是对象输出流将一个对象转换的字节
*
* 将一个Person类型的实例写入文件person
.obj
实例:
String name
= "苍老师";
int age
= 18;
String gender
= "女";
String
[] otherInfo
= {"是一名演员","爱好写毛笔字","促进中日文化交流","广大男性同胞的启蒙老师"};
Person p
= new Person(name
,age
,gender
,otherInfo
);
System
.out
.println(p
);
FileOutputStream fos
= new FileOutputStream("person.obj");
ObjectOutputStream oos
= new ObjectOutputStream(fos
);
oos
.writeObject(p
);
System
.out
.println("写出完毕!");
oos
.close();
* 对象输入流
实例:
FileInputStream fis
= new FileInputStream("person.obj");
ObjectInputStream ois
= new ObjectInputStream(fis
);
Person p
= (Person
)ois
.readObject();
System
.out
.println(p
);
ois
.close();
* 使用该类测试对象流的对象读写操作
*
* 一个类的实例若希望被对象流读写,那么必须实现接口
:
* java
.io
.Serializable
* 该接口不需要重写任何方法,但是实际上编译器在编译当前
* 类时若发现其实现了可序列化接口时,会隐含的添加一个方法
* 作用是将当前类实例转换为一组字节。而该方法不需要体现在
* 源代码中。
* 当一个类实现了序列化接口后,需要定义一个常量
:
* serialVersionUID 序列化版本号
* 若不指定,则当前类在编译时,编译器会结合当前
* 源代码生成一个版本号,但这意味着当前类的源码
* 做出改动,版本号就会变化。
* 而版本号影响着反序列化的结果。
* 当对象输入流在读取一个对象进行反序列化时,会检查
* 该对象与当前类的版本号是否一致,一致则可以反序列化
* 但是不一致则会抛出异常。
private static final long serialVersionUID
= 1L
;
* 当一个属性被
transient修饰后,在进行对象序列化时
* 该属性的值会被忽略。这意味着反序列化时得不到该
* 属性的值。
* 忽略不必要的属性,可以做到对象序列化时的
"瘦身"效果
* 减少资源开销。
private transient String
[] otherInfo
;
BufferedReader && BufferedWriter
* 缓冲字符输入流
* java
.io
.BufferedReader
* 特点
:可以按行读取字符串
实例:
* 将当前源代码读取出来并输出到控制台
FileInputStream fis
= new FileInputStream("src/io/BufferedReaderDemo.java");
InputStreamReader isr
= new InputStreamReader(fis
);
BufferedReader br
= new BufferedReader(isr
);
String line
= null
;
while((line
= br
.readLine())!=null
) {
System
.out
.println(line
);
}
br
.close();
public static void BufReadWrite() throws IOException
{
FileInputStream fis
= new FileInputStream("pom.xml");
InputStreamReader isr
=new InputStreamReader(fis
,"UTF-8");
BufferedReader br
=new BufferedReader(isr
);
FileOutputStream fos
=new FileOutputStream("bufWR.txt");
OutputStreamWriter osw
=new OutputStreamWriter(fos
, "UTF-8");
BufferedWriter bw
=new BufferedWriter(osw
);
String line
=null
;
while((line
=br
.readLine())!=null
) {
bw
.write(line
);
}
System
.out
.println("读写成功!");
br
.close();
bw
.close();
}
Reader && Writer
* 字符流
* java按照流读写的数据单位划分为
:字节流与字符流
* 由于读写文本数据是一件非常频繁的操作,对此java专门设计
* 了一套流,字符流。字符流是以字符为单位读写数据的,虽然
* 底层实际上还是读写字节
(因为计算机只有二进制
),但是字节
* 与字符之间的转换工作字符流自行完成了。对此也要注意到
* 字符流的局限性,仅适合读写文本数据。
*
* java
.io
.Reader和java
.io
.Writer
* 这两个类也是抽象类,它们分别是所有字符输入流与字符输出
* 流的超类,规定了字符流读写字符的相关方法。
InputStreamReader && OutputStreamWriter
* 转换流
:
* java
.io
.InputStreamReader
,java
.io
.OutputStreamWriter
* 它们是字符流的一对常用实现类,在使用字符流读写数据时,
* 作为流链接的重要一环存在。但实际应用时我们通常不会直接
* 操作这两个流
(因为其上还会链接其他高级的字符流
)。
实例:
FileOutputStream fos
= new FileOutputStream("osw.txt");
OutputStreamWriter osw
= new OutputStreamWriter(fos
,"UTF-8");
osw
.write("在一瞬间有一百万种可能。");
osw
.write("该向前走还是继续等。");
System
.out
.println("写出完毕!");
osw
.close();
public static void ISRW() throws IOException
{
FileOutputStream fos
=new FileOutputStream("IOSrw.txt");
OutputStreamWriter osw
=new OutputStreamWriter(fos
,"UTF-8");
osw
.write("在一瞬间有一百万种可能!");
osw
.close();
FileInputStream fis
=new FileInputStream("IOSrw.txt");
InputStreamReader isr
=new InputStreamReader(fis
,"UTF-8");
char[] data
=new char[1024];
while(isr
.read(data
)!=-1) {
System
.out
.println(data
);
}
isr
.close();
}
* InputStreamReader与OutputStreamWriter之所以称为
* "转换流",是因为其他的高级字符流都只能连接在其他的
* 字符流上,而不能直接连接在字节流上,而转换流是唯一
* 可以连接在字节流上的字符流,而它们本身是字符流,可以
* 供其他字符流连接,从而起到承上启下的作用。对此我们在
* 使用字符流操作时,它们在流链接中是用来衔接字节流与
* 字符流的桥梁。负责将字符与字节之间相互转换。
实例:
FileInputStream fis
= new FileInputStream("osw.txt");
InputStreamReader isr
= new InputStreamReader(fis
,"UTF-8");
int d
= -1;
char[] data
= new char[100];
int len
= isr
.read(data
);
String str
= new String(data
,0,len
);
System
.out
.println(str
);
isr
.close();
PrintWriter
* java
.io
.PrintWriter
* 具有自动行刷新的缓冲字符输出流
* 注
:java
.io
.BufferedWriter是缓冲字符输出流,PW总是会
* 在内部链接它来完成缓冲工作,而PW在其基础上还支持自动的
* 行刷新操作,所以更为常用。
*
* 缓冲字符输出流除了写出字符效率高之外,还可以按行写出
* 字符串
(写出个字符串后会自动添加换行符
)。
实例:
* PW提供了直接写文件的构造方法
* PrintWriter(String path
)
* PrintWriter(File file
)
*
* 也支持重载构造方法,第二个参数为字符集,这样就
* 可以按照指定的字符集将字符写入文件。
*/
PrintWriter pw
= new PrintWriter("pw.txt","UTF-8");
pw
.println("让我掉下眼泪的,不止昨夜的酒。");
pw
.println("让我依依不舍的,不止你的温柔。");
System
.out
.println("写出完毕!");
pw
.close();
public static void PWFileIO() throws IOException
{
PrintWriter pw
=new PrintWriter("pw.txt","UTF-8");
pw
.println("让我掉下眼泪的,不止昨夜的酒。");
pw
.println("让我掉下眼泪的,不止昨夜的酒。");
pw
.print("让我掉下眼泪的,不止昨夜的酒。");
pw
.flush();
pw
.close();
System
.out
.println("写入成功!");
}
* 在流链接中使用PrintWriter
实例:
FileOutputStream fos
= new FileOutputStream("pw.txt");
OutputStreamWriter osw
= new OutputStreamWriter(fos
,"UTF-8");
BufferedWriter bw
= new BufferedWriter(osw
);
PrintWriter pw
= new PrintWriter(bw
);
pw
.println("巴拉巴");
System
.out
.println("写出完毕!");
pw
.close();
Date time
=new Date();
SimpleDateFormat sdf
=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
FileOutputStream fos
= new FileOutputStream("D:/logs/YL_logs.txt",true);
PrintWriter pw
= new PrintWriter(new BufferedWriter(new OutputStreamWriter(fos
, "UTF-8")));
pw
.println("时间:"+sdf
.format(time
));
pw
.close();
* 完成简易记事本工具
* 输入文件名,对文件写操作,之后输入的每行字符串都
* 按行写入到文件中,当输入exit时程序退出。
*
* 注
:创建PrintWriter使用流链接。
实例:
Scanner scanner
= new Scanner(System
.in
);
System
.out
.println("请输入文件名:");
String fileName
= scanner
.nextLine();
FileOutputStream fos
= new FileOutputStream(fileName
);
OutputStreamWriter osw
= new OutputStreamWriter(fos
,"UTF-8");
BufferedWriter bw
= new BufferedWriter(osw
);
PrintWriter pw
= new PrintWriter(bw
,true);
System
.out
.println("请开始输入:");
while(true) {
String line
= scanner
.nextLine();
if("exit".equals(line
)) {
break;
}
pw
.println(line
);
}
System
.out
.println("再见!");
pw
.close();
try-catch && finally
* java异常处理机制中的
try-catch
* 语法
:
* try{
* 可能出现异常的代码片段
* }catch(XXXException e
){
* 当
try中出现XXXException后的解决办法
* }
实例:
System
.out
.println("程序开始了");
try {
String str
= "a";
System
.out
.println(str
.length());
System
.out
.println(str
.charAt(0));
System
.out
.println(Integer
.parseInt(str
));
System
.out
.println("!!!!!!!");
}catch(NullPointerException e
) {
System
.out
.println("出现了空指针!");
}catch(StringIndexOutOfBoundsException e
) {
System
.out
.println("字符串下标越界了!");
}catch(Exception e
) {
System
.out
.println("反正就是出了个错!");
}
System
.out
.println("程序结束了");
* 自动关闭特性
* JDK7之后推出的,使得我们在IO操作中的异常处理写法更简洁。
实例:
try(FileOutputStream fos
= new FileOutputStream("fos.dat",true))
{
fos
.write(1);
} catch (Exception e
) {
System
.out
.println("出错了!");
}
* finally块
* finally块是异常处理机制的最后一块。它可以直接跟在
try块之后或者最后一个
catch块之后。
* finally确保只要程序执行到
try块中,那么
finally块中的代码必定执行。
* 所以通常我们将无关乎程序是否出现异常,都要执行的代码放在其中,比如IO操作后的关闭流。
实例:
System
.out
.println("程序开始了");
try {
String str
= "";
System
.out
.println(str
.length());
return;
} catch (Exception e
) {
System
.out
.println("出错了!");
} finally {
System
.out
.println("finally中的代码运行了!");
}
System
.out
.println("程序结束了");
* try 后面可以连接多个
catch
实例:
try {
System
.out
.println("test方法执行了...");
return str
.charAt(0)-'0';
} catch (NullPointerException e
) {
System
.out
.println("出现了空指针!");
return 1;
} catch (Exception e
) {
System
.out
.println("出现了其他异常!");
return 2;
} finally {
System
.out
.println("执行了finally!");
return 3;
}
--------TCP网络通信编程--------
java
.net
.ServerSocket
;
java
.net
.Socket
;
创建服务端套接字:ServerSocket server
=new ServerSocket(8088);
监听:Socket socket
= server
.accpet();
创建客户端套接字:Socket socket
=new Socket("192.168.2.112",8088);
--------多线程编程--------
线程
线程可以并发执行多段代码,给我们感觉上好像这些代码在"同时运行"。创建线程有两种方式:
方式一:继承Thread并重写run方法。
启动线程要调用start方法,而不是直接调用线程的run方法。 * 第一种创建线程的方式存在两个不足之处1:由于java是单继承的,这导致继承了Thread后就不能再继承其他类了。在实际开发中经常会继承某个超类来复用其中的方法,这导致两者不能同时继承。2:继承线程后重写run方法来定义任务,这又导致我们将任务直接定义在线程上,使得线程只能做该任务,无法并发 执行其他任务,重用性变差。
方式一:Runnable
* 实现Runnable接口,单独定义线程任务
实例:
class MyRunnable1 implements Runnable{
public void run() {
for(int i
=0;i
<1000;i
++) {
System
.out
.println("你是谁啊?");
}
}
}
Runnable r1
= new MyRunnable1();
Thread t1
= new Thread(r1
);
t1
.start();
public static void main(String
[] args
) {
System
.out
.println("主线程执行开始!");
Thread th
=new Thread() {
@Override
public void run() {
System
.err
.println("Thread 内部类实现多线程!");
}
};
Thread thr
=new Thread(new Runnable() {
@Override
public void run() {
System
.err
.println("通过Runnable匿名内部类实现多线程!");
}
});
th
.start();
thr
.start();
System
.out
.println("主线程执行结束!");
}
线程提供了一系列获取当前线程信息的方法
实例:
Thread main
= Thread
.currentThread();
long id
= main
.getId();
System
.out
.println("id:"+id
);
String name
= main
.getName();
System
.out
.println("name:"+name
);
int priority
= main
.getPriority();
System
.out
.println("priority:"+priority
);
boolean isAlive
= main
.isAlive();
boolean isDaemon
= main
.isDaemon();
boolean isInterrupted
= main
.isInterrupted();
System
.out
.println("是否活着:"+isAlive
);
System
.out
.println("是否为守护线程:"+isDaemon
);
System
.out
.println("是否被中断:"+isInterrupted
);
static Thread currentThread
* Thread提供了一个静态方法
:
* static Thread
currentThread()
* 该方法可以获取运行这个方法的线程。
* 后期常用的一个API
: ThreadLocal里面就会用到这个方法来实现功能。
实例:
Thread main
= Thread
.currentThread();
System
.out
.println("运行main方法的线程是:"+main
);
Thread t
= new Thread() {
public void run() {
Thread t
= Thread
.currentThread();
System
.out
.println("自定义线程:"+t
);
dosome();
}
};
t
.start();
线程优先级
* 线程无法主动获取CPU时间片,唯一可以干涉线程调度工作
* 的方式就是修改线程优先级,最大程度的改善获取CPU时间
* 片的几率。
* 理论上,线程优先级越高的线程获取CPU时间片的次数越多
* 线程有
10个优先级,分别用整数
1-10表示。
实例:
Thread max
= new Thread() {
public void run() {
for(int i
=0;i
<10000;i
++) {
System
.out
.println("max");
}
}
};
Thread min
= new Thread() {
public void run() {
for(int i
=0;i
<10000;i
++) {
System
.out
.println("min");
}
}
};
Thread norm
= new Thread() {
public void run() {
for(int i
=0;i
<10000;i
++) {
System
.out
.println("nor");
}
}
};
max
.setPriority(Thread
.MAX_PRIORITY
);
min
.setPriority(Thread
.MIN_PRIORITY
);
min
.start();
norm
.start();
max
.start();
join方法可以协调线程之间的同步运行
* 异步运行
:代码之间运行没有先后顺序,各干各的。
* 同步运行
:代码运行有先后顺序。
实例:
final Thread download
= new Thread() {
public void run() {
System
.out
.println("down:开始下载图片...");
for(int i
=1;i
<=100;i
++) {
System
.out
.println("down:已下载"+i
+"%");
try {
Thread
.sleep(50);
} catch (InterruptedException e
) {
}
}
System
.out
.println("down:图片下载完毕!");
isFinish
= true;
}
};
Thread show
= new Thread() {
public void run() {
System
.out
.println("show:开始显示图片...");
try {
download
.join();
} catch (InterruptedException e
) {
}
if(!isFinish
) {
throw new RuntimeException("图片加载失败!");
}
System
.out
.println("show:显示图片完毕!");
}
};
download
.start();
show
.start();
睡眠阻塞
* static void sleep(long ms
)
* 该方法会让运行这个方法的线程处于阻塞状态指定的毫秒,
* 当超时后,线程会自动回到RUNNABLE状态,等待再次获取
* 时间片并发运行。
*
* 注:一个线程进入阻塞状态时,CPU会立刻释放去并发执行
* 其他线程,直到该线程解除阻塞状态为止。
实例:
Scanner scanner
= new Scanner(System
.in
);
System
.out
.println("请输入一个数字:");
int num
= Integer
.parseInt(scanner
.nextLine());
for(int i
=num
;i
>0;i
--) {
System
.out
.println(i
);
try {
Thread
.sleep(1000);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
}
System
.out
.println("结束.");
多线程并发的安全问题
* 当多个线程并发操作同一资源时,由于线程切换时机的不确定
* 和不可控,会导致操作该资源的代码逻辑执行顺序未按照设计
* 要求运行,出现了操作混乱。严重时可能导致系统瘫痪。
* 解决并发安全问题的核心就是将多个线程抢着运行改为
* 有先后顺序的排队运行。
* Java提供了锁机制,强制多个线程同步运行一个方法
*
* 当一个方法上使用关键字
:synchronized修饰后,该方法
* 称为同步方法,多个线程不能同时在方法内部运行。
实例:
public synchronized int getBean() {
if(beans
==0) {
throw new RuntimeException("没有豆子了!");
Thread
.yield();
return beans
--;
}
* 同步块
* 有效的缩小同步范围可以在保证并发安全的前提下尽可能的提高并发执行效率。
*
* 语法
:
* synchronized(同步监视器对象
){
* 需用同步运行的代码片段
* }
实例:
class Shop{
public void buy() {
try {
Thread t
= Thread
.currentThread();
System
.out
.println(t
.getName()+":正在挑衣服...");
Thread
.sleep(5000);
synchronized (this) {
System
.out
.println(t
.getName()+":正在试衣服...");
Thread
.sleep(5000);
}
System
.out
.println(t
.getName()+":结账离开");
} catch (Exception e
) {
System
.out
.println("出现异常了");
}
}
}
* 静态方法若使用
synchronized修饰后,那么一定具有同步
(静态方法属于类,只有一份,使用时必须一次等待)
public synchronized static void dosome() {
try {
Thread t
= Thread
.currentThread();
System
.out
.println(t
.getName()+":正在运行dosome方法");
Thread
.sleep(5000);
System
.out
.println(t
.getName()+":运行dosome方法完毕");
} catch (Exception e
) {
e
.printStackTrace();
}
}
守护线程
* 守护线程又称为后台线程,默认创建出来的线程都是普通
* 线程或称为前台线程。只有调用线程的setDaemon方法后
* 才会将该线程设置为守护线程。
*
* 守护线程使用上与前台线程一样,但是在结束时机上有一点
* 不同
:当进程结束时,所有正在运行的守护线程都会被强制
* 中断。
* 进程的结束
:当一个进程中没有任何前台线程时即结束。
* 设置守护线程必须要在start方法之前进行。
jack
.setDaemon(true);
jack
.start();
--------线程池--------
* 线程池
* 线程池是一个管理线程的机制。它主要解决两个问题:
* 1:重用线程
* 2:控制线程数量
* 频繁的创建和销毁线程会给系统带来额外的开销,所以线程应当得以重用。
* 当线程数量过多时,会出现资源消耗增大,CPU出现过渡切换导致并发性能降低,
* 对此线程的数量也要得以控制在当前硬件环境所能承受的范围内。
实例:
public static void main(String
[] args
) {
ExecutorService threadPool
=Executors
.newFixedThreadPool(2);
for(int i
=0;i
<5;i
++)
{
Runnable r
=new Runnable(){
@Override
public void run() {
Thread t
=Thread
.currentThread();
System
.out
.println(t
.getName()+":执行任务完毕!");
}
};
threadPool
.execute(r
);
System
.out
.println("将一个任务指派给了线程池"+i
+"!");
}
threadPool
.shutdown();
}
--------集合Collection(List & Set)--------
java.util.Collection
* 集合框架
* Collection接口是所有集合的顶级接口,规定了所有集合都应当具备的功能。
* 其下常见的分类
:
* java
.util
.List
:可重复集合
,有序集
* java
.util
.Set
:不可重复集合,无序
* 重复指的是元素是否重复,而标准是元素自身equals比较的结果。
实例:
Collection c
= new ArrayList();
c
.add("one");
c
.add("two");
c
.add("three");
c
.add("four");
c
.add("five");
System
.out
.println(c
);
int size
= c
.size();
System
.out
.println("size:"+size
);
boolean isEmpty
= c
.isEmpty();
System
.out
.println("isEmpty:"+isEmpty
);
c
.clear();
System
.out
.println("集合已清空");
System
.out
.println(c
);
System
.out
.println("size:"+c
.size());
System
.out
.println("isEmpty:"+c
.isEmpty());
* 集合存放的是元素的引用
Collection c
= new ArrayList();
Point p
= new Point(1,2);
* 集合操作
Collection c1
= new ArrayList();
c1
.add("java");
c1
.add("c");
c1
.add("c++");
System
.out
.println("c1:"+c1
);
Collection c2
= new HashSet();
c2
.add("android");
c2
.add("ios");
System
.out
.println("c2:"+c2
);
c1
.addAll(c2
);
System
.out
.println("c1:"+c1
);
Collection c3
= new ArrayList();
c3
.add("java");
c3
.add("ios");
c3
.add("php");
boolean contains
= c1
.containsAll(c3
);
System
.out
.println("c1全包含c3:"+contains
);
c1
.removeAll(c3
);
System
.out
.println("c1:"+c1
);
* 泛型应用最广泛的地方就是集合,而集合中使用泛型是用来约束集合的元素类型
public static void main(String
[] args
) {
Collection
<String> c
= new ArrayList<String>();
c
.add("one");
c
.add("two");
c
.add("three");
c
.add("four");
System
.out
.println(c
);
for(String str
: c
) {
System
.out
.println(str
);
}
Iterator
<String> it
= c
.iterator();
while(it
.hasNext()) {
String str
= it
.next();
System
.out
.println(str
);
}
}
contains
* 集合可以判断是否包含给定元素,方法为
:
* boolean contains(Object o
)
* 当包含给定元素时返回
true
public static void main(String
[] args
) {
Collection c
= new ArrayList();
c
.add(new Point(1,2));
c
.add(new Point(3,4));
c
.add(new Point(5,6));
c
.add(new Point(7,8));
c
.add(new Point(9,0));
System
.out
.println(c
);
Point p
= new Point(1,2);
boolean contains
= c
.contains(p
);
System
.out
.println("包含:"+contains
);
}
iterator
* 遍历集合元素
*
* Collection提供了一个方法
:
* Iterator
iterator()
* 该方法可以获取一个用于遍历当前集合元素的迭代器。
*
* java
.util
.Iterator接口
* 该接口是所有迭代器的顶级接口,规定了迭代器遍历集合的
* 统一操作。不同的集合实现类都实现了一个用于遍历自身元素
* 的迭代器实现类。我们无需记住它们,用接口接收它们并调用
* 相应遍历方法即可。
public static void main(String
[] args
) {
Collection c
= new ArrayList();
c
.add("one");
c
.add("#");
c
.add("two");
c
.add("#");
c
.add("three");
c
.add("#");
c
.add("four");
c
.add("#");
c
.add("five");
System
.out
.println(c
);
Iterator it
= c
.iterator();
while(it
.hasNext()) {
String str
= (String
)it
.next();
System
.out
.println(str
);
if("#".equals(str
)) {
it
.remove();
}
}
System
.out
.println(c
);
}
for each
* JDK5推出时,推出了一个新的特性
:
* 增强型
for循环,也称为新循环,
for each
*
* 新循环不取代传统循环的工作,只用来遍历集合或数组。
*
* 注:新循环的语法JVM是不认可的,而只是编译器认可,
* 编译器在编译源程序时会将新循环遍历改为传统方式遍历。
public static void main(String
[] args
) {
String
[] array
= {"one","two","three","four"};
for(int i
=0;i
<array
.length
;i
++) {
String str
= array
[i
];
System
.out
.println(str
);
}
for(String str
:array
) {
System
.out
.println(str
);
}
System
.out
.println("=====================");
Collection c
= new ArrayList();
c
.add("one");
c
.add("two");
c
.add("three");
c
.add("four");
c
.add("five");
for(Object o
: c
) {
String str
= (String
)o
;
System
.out
.println(str
);
}
}
*删除集合元素
* remove方法删除元素时是删除与给定元素equals
* 比较为
true的元素。注意
:List集合而言,若存在
* 重复元素,只删除一个。
*/
c
.remove(p
);
泛型
* 泛型不指定则默认为原型Object
* 泛型是JDK5推出的一个特性,又称为参数化类型。允许使用
* 者在使用一个类的时候指定其定义的属性,方法的参数以及
* 返回值的类型。这样可以使得程序使用更灵活。
* 实际上编译后,Type类型名后面没有
<T>.
* 而
:
* private T x
;
* 会被改为
* private Object x
;
* 参数也会改为
:
* public Type(Object x
, Object y
) {
*
* 下面的方法同理,返回值若是T,也会被改为Object。
泛型实例:
public static void main(String
[] args
) {
Type
<Integer> t1
= new Type<Integer>(1,2);
t1
.setX(2);
int x1
= t1
.getX();
System
.out
.println("x1:"+x1
);
System
.out
.println("t1:"+t1
);
Type
<Double> t2
= new Type<Double>(1.1,2.2);
double x2
= t2
.getX();
System
.out
.println("x2:"+x2
);
System
.out
.println("t2:"+t2
);
Type
<String> t3
= new Type<String>("一","二");
String x3
= t3
.getX();
System
.out
.println("x3:"+x3
);
System
.out
.println("t3:"+t3
);
}
toArray
* Collection中提供了一个方法
:toArray
* 可以将当前集合转换为一个数组。
实例:
Collection
<String> c
= new ArrayList<String>();
c
.add("one");
c
.add("two");
c
.add("three");
c
.add("four");
System
.out
.println(c
);
String
[] array
= c
.toArray(new String[c
.size()]);
System
.out
.println(array
.length
);
System
.out
.println(Arrays
.toString(array
));
java.util.List
* java
.util
.List
* List接口是Collection的一个子接口,称为线性表。
*
* List集合的特点
:可以重复,并且有序。提供了一组通过下标操作元素的方法。
* 常见实现类
:
* java
.util
.ArrayList
:数组实现,查询性能更好
* java
.util
.LinkedList
:链表实现,增删元素性能更好,尤其首尾增删元素效果最优。
实例:
List
<String> list
= new ArrayList<String>();
list
.add("one");
list
.add("two");
list
.add("three");
list
.add("four");
list
.add("five");
System
.out
.println(list
);
String str
= list
.get(1);
System
.out
.println(str
);
for(int i
=0;i
<list
.size();i
++) {
str
= list
.get(i
);
System
.out
.println(str
);
}
String old
= list
.set(1, "2");
System
.out
.println(list
);
System
.out
.println("old:"+old
);
List —> add && remove
* List提供了一对重载的add
,remove方法。都是支持通过
* 下标操作对应元素
实例:
List
<String> list
= new ArrayList<String>();
list
.add("one");
list
.add("two");
list
.add("three");
System
.out
.println(list
);
list
.add(1, "2");
System
.out
.println(list
);
String old
= list
.remove(2);
System
.out
.println(list
);
System
.out
.println("old:"+old
);
List —> subList && asList
* List提供获取子集的操作
:
*
* List
subList(int start
,int end
)
* 获取指定范围内的子集
实例:
List
<Integer> list
= new ArrayList<Integer>();
for(int i
=0;i
<10;i
++) {
list
.add(i
);
}
System
.out
.println(list
);
List
<Integer> subList
= list
.subList(3, 8);
System
.out
.println(subList
);
for(int i
=0;i
<subList
.size();i
++) {
int num
= subList
.get(i
);
num
= num
*10;
subList
.set(i
, num
);
}
System
.out
.println(subList
);
System
.out
.println(list
);
list
.subList(2, 9).clear();
System
.out
.println(list
);
* 数组转换为集合
* 数组的工具类Arrays提供了一个静态方法
:asList
* 可以将一个数组转换为一个List集合。
实例:
public static void main(String
[] args
) {
String
[] array
= {"one","two","three","four"};
System
.out
.println("Array:"+Arrays
.toString(array
));
List
<String> list
= Arrays
.asList(array
);
System
.out
.println("list:"+list
);
list
.set(1, "2");
System
.out
.println("list:"+list
);
System
.out
.println("Array:"+Arrays
.toString(array
));
List
<String> list2
= new ArrayList<String>(list
);
System
.out
.println("list2:"+list2
);
list2
.add("five");
System
.out
.println("list2:"+list2
);
}
synchronizedList && synchronizedSet
* Collections提供了将现有的集合转换为并发安全的集合
实例:
public static void main(String
[] args
) {
List
<String> list
= new ArrayList<String>();
list
.add("one");
list
.add("two");
list
.add("three");
list
.add("four");
list
= Collections
.synchronizedList(list
);
System
.out
.println(list
);
Set
<String> set
= new HashSet<String>(list
);
set
= Collections
.synchronizedSet(set
);
System
.out
.println(set
);
}
栈
* 栈也可以保存一组元素,存取必须遵循先进后出原则
*
* 使用栈一般是为了实现如
"后退"这样的功能
实例:
public static void main(String
[] args
) {
Deque
<String> stack
= new LinkedList<String>();
stack
.push("one");
stack
.push("two");
stack
.push("three");
stack
.push("four");
System
.out
.println(stack
);
String str
= stack
.pop();
System
.out
.println(str
);
System
.out
.println(stack
);
for(String s
: stack
) {
System
.out
.println(s
);
}
System
.out
.println(stack
);
}
集合的排序
*排序字符串
实例:
List
<String> list
= new ArrayList<String>();
list
.add("tom");
list
.add("jerry");
list
.add("JACK");
list
.add("TOMAS");
list
.add("MIKE");
list
.add("bill");
list
.add("jackson");
list
.add("michell");
System
.out
.println(list
);
Collections
.sort(list
);
System
.out
.println(list
);
* 集合的排序
* 集合有一个工具类
:java
.util
.Collections
* 它提供了很多便于我们操作集合的静态方法,其中有一个
* 方法是
:sort
,用于对List集合进行自然排序。
实例:
public static void main(String
[] args
) {
Random random
= new Random();
List
<Integer> list
= new ArrayList<Integer>();
for(int i
=0;i
<10;i
++) {
list
.add(random
.nextInt(100));
}
System
.out
.println(list
);
Collections
.sort(list
);
System
.out
.println(list
);
}
public static void main(String
[] args
) {
List
<String> list
= new ArrayList<String>();
list
.add("苍老师");
list
.add("传奇");
list
.add("小泽老师");
System
.out
.println(list
);
Collections
.sort(list
);
System
.out
.println(list
);
sortString(list
);
List
<Point> list2
= new ArrayList<Point>();
list2
.add(new Point(2,3));
list2
.add(new Point(8,9));
list2
.add(new Point(4,6));
list2
.add(new Point(1,1));
list2
.add(new Point(5,0));
System
.out
.println(list2
);
sortPoint(list2
);
}
public static void sortPoint(List
<Point> list
) {
Collections
.sort(list
,new Comparator<Point>() {
public int compare(Point o1
, Point o2
) {
int len1
= o1
.getX()*o1
.getX()+o1
.getY()*o1
.getY();
int len2
= o2
.getX()*o2
.getX()+o2
.getY()*o2
.getY();
return len1
-len2
;
}
});
System
.out
.println("排序Point后的结果:"+list
);
}
public static void sortString(List
<String> list
) {
Collections
.sort(list
,new Comparator<String>() {
public int compare(String o1
, String o2
) {
return o1
.length()-o2
.length();
}
});
System
.out
.println("自定义排序效果:"+list
);
}
Queue
* java
.util
.Queue接口
* Queue是队列,其继承自Collection。
* 队列可以保存一组元素,但是存取元素必须遵循先进先出原则
*
* 常用实现类
:java
.util
.LinkedList
实例:
public static void main(String
[] args
) {
Queue
<String> queue
= new LinkedList<String>();
queue
.offer("one");
queue
.offer("two");
queue
.offer("three");
queue
.offer("four");
System
.out
.println(queue
);
String str
= queue
.poll();
System
.out
.println(str
);
System
.out
.println(queue
);
str
= queue
.peek();
System
.out
.println(str
);
System
.out
.println(queue
);
for(String s
: queue
) {
System
.out
.println(s
);
}
System
.out
.println(queue
);
while(queue
.size()>0) {
String s
= queue
.poll();
System
.out
.println(s
);
}
System
.out
.println(queue
);
}
Deque
* 双端队列 java
.util
.Deque
* 它继承自Queue
,是两端都可以进出队的队列。
*
* 常用实现类
:java
.util
.LinkedList
public static void main(String
[] args
) {
Deque
<String> deque
= new LinkedList<String>();
deque
.offer("one");
deque
.offer("two");
deque
.offer("three");
System
.out
.println(deque
);
deque
.offerFirst("four");
System
.out
.println(deque
);
deque
.offerLast("five");
System
.out
.println(deque
);
String str
= deque
.poll();
System
.out
.println(str
);
System
.out
.println(deque
);
str
= deque
.pollLast();
System
.out
.println(str
);
System
.out
.println(deque
);
str
= deque
.pollFirst();
System
.out
.println(str
);
System
.out
.println(deque
);
}
BlockingQueue
* 阻塞队列
* 阻塞队列是并发安全的队列,采用双缓冲,在并发安全的前提下解决存取互斥问题,并发效率更好
实例:
public static void main(String
[] args
) {
BlockingQueue
<String> queue
= new ArrayBlockingQueue<String>(3);
boolean b
= queue
.offer("one");
System
.out
.println(b
);
queue
.offer("two");
queue
.offer("three");
try {
b
= queue
.offer("four", 5, TimeUnit
.SECONDS
);
} catch (InterruptedException e
) {
e
.printStackTrace();
}
System
.out
.println(b
);
System
.out
.println(queue
);
}
Map
* java
.util
.Map 查找表
* Map体现的结构是一个多行两列的表格
* 左列名为key,右列名为value
* value是保存要查找的值,而对应的key是查询条件。
*
* 在一个Map中key是不允许重复的。
*
* 常用实现类
:java
.util
.HashMap
* 也称为散列表或哈希表
* 当今世界上查询速度最快的数据结构。
实例:
public static void main(String
[] args
) {
Map
<String,Integer> map
= new HashMap<String,Integer>();
Integer num
= map
.put("语文", 98);
System
.out
.println(num
);
map
.put("数学", 97);
map
.put("英语", 96);
map
.put("物理", 95);
map
.put("化学", 98);
System
.out
.println(map
);
num
= map
.put("语文", 88);
System
.out
.println(num
);
System
.out
.println(map
);
num
= map
.get("数学");
System
.out
.println("数学:"+num
);
num
= map
.get("体育");
System
.out
.println("体育:"+num
);
num
= map
.remove("数学");
System
.out
.println(map
);
System
.out
.println(num
);
int size
= map
.size();
System
.out
.println("size:"+size
);
boolean ck
= map
.containsKey("语文");
System
.out
.println("包含key:"+ck
);
boolean cv
= map
.containsValue(96);
System
.out
.println("包含value:"+cv
);
}
Map的遍历
* Map提供了三种遍历方式
:
* 1:遍历所有的key
* 2:遍历所有的键值对
(Entry
)
* 3:遍历所有的
value(相对不常用
)
实例:
public static void main(String
[] args
) {
Map
<String,Integer> map
= new HashMap<String,Integer>();
map
.put("语文", 98);
map
.put("数学", 97);
map
.put("英语", 96);
map
.put("物理", 95);
map
.put("化学", 98);
System
.out
.println(map
);
Set
<String> keySet
= map
.keySet();
for(String key
: keySet
) {
System
.out
.println("key:"+key
);
}
Set
<Entry
<String,Integer>> entrySet
= map
.entrySet();
for(Entry
<String,Integer> e
: entrySet
) {
String key
= e
.getKey();
Integer value
= e
.getValue();
System
.out
.println(key
+":"+value
);
}
Collection
<Integer> values
= map
.values();
for(Integer value
: values
) {
System
.out
.println("value:"+value
);
}
}
--------反射机制--------
* java的反射机制
*
* 反射允许们在实例化一个类,操作其属性和方法从编码期决定转为在运行期决定。
* 这样做可以提高代码的灵活性,适度使用,过度使用会降低代码的运行效率,增加资源开销。
实例:
public static void main(String
[] args
) {
try {
Class
<?> cls
=Class
.forName("reflect.Person");
String name
=cls
.getName();
System
.out
.println(name
);
} catch (ClassNotFoundException e
) {
e
.printStackTrace();
}
}
* 通过类对象,可以获取其表示的类的一切信息:类名、属性、方法、构造器 等等。
* 并且可以通过调用无参构造器快速实例化一个对象。
实例:
public static void main(String
[] args
) throws InstantiationException
, IllegalAccessException
{
try {
Class
<?> cls
=Class
.forName("reflect.Person");
Constructor
<?>[] arr
=cls
.getConstructors();
for(Constructor
<?> cos
:arr
)
{
System
.out
.println(cos
);
}
Method
[] arr1
=cls
.getDeclaredMethods();
for(Method met
:arr1
)
{
System
.out
.println(met
);
}
Person p
=new Person();
System
.out
.println(p
);
Object obj
=cls
.newInstance();
System
.out
.println(obj
);
Person ob
=(Person
)obj
;
ob
.sayHi();
} catch (ClassNotFoundException e
) {
e
.printStackTrace();
}
}
* 通过反射机制调用无参方法
public static void main(String
[] args
) throws Exception
{
Class
cls=Class
.forName("reflect.Person");
Object obj
=cls
.newInstance();
Method method
=cls
.getDeclaredMethod("sayHi",null
);
method
.invoke(obj
,null
);
}
* 调用有参数方法
public static void main(String
[] args
) {
try {
Class
<?> cls
=Class
.forName("reflect.Person");
Object obj
=cls
.newInstance();
Method method
=cls
.getDeclaredMethod("sayHello",String
.class,int.class);
method
.invoke(obj
, "是这么一回事儿!",12);
} catch (Exception e
) {
e
.printStackTrace();
}
}
反射综合案例:
public static void main(String
[] args
) throws ClassNotFoundException
,IllegalArgumentException
,Exception
{
Scanner scan
=new Scanner(System
.in
);
System
.out
.println("请输入反射类全名:");
String name
=scan
.nextLine();
Class
<?> cls
=Class
.forName(name
);
Object obj
=cls
.newInstance();
Method
[] methods
=cls
.getDeclaredMethods();
for(Method me
:methods
){
System
.out
.println(me
.getName());
Class
[] types
=me
.getParameterTypes();
Object returnVal
=null
;
if(types
.length
==0){
returnVal
=me
.invoke(obj
);
}else{
Object
[] params
=new Object[types
.length
];
for(int i
=0;i
<types
.length
;i
++){
if(types
[i
]==String
.class){
params
[i
]="HelloWorld!";
}
if(types
[i
]==int.class){
params
[i
]=100;
}
}
returnVal
=me
.invoke(obj
,params
);
}
System
.out
.println("returnVal:"+returnVal
);
}
scan
.close();
}
--------日期类--------
Date
* java
.util
.Date
* 日期类,其中每一个实例用于表示一个切确的时间点。
* Date内部维护了一个
long值,该值为自公元
1970-01-01 00:00:00 到其表示的时间之间所经过的毫秒。
* 由于Date存在失去和千年虫的问题,大部分操作时间的方法在jdk1
.1版本出现时就变为过时方法了,不在建议使用。
实例:
public static void main(String
[] args
) {
Date date
=new Date();
System
.out
.println(date
);
long mill
=date
.getTime();
System
.out
.println(mill
);
date
.setTime(0);
String time
=date
.toString();
System
.out
.println(time
);
}
* java
.util
.SimpleDateFormat
public static void main(String
[] args
) {
Date now
=new Date();
System
.out
.println(now
);
String str
="yyyy-MM-dd HH:mm:ss";
SimpleDateFormat sdf
=new SimpleDateFormat(str
);
String line
=sdf
.format(now
);
System
.out
.println(line
);
}
* 将一个字符串解析为Date
public static void main(String
[] args
) throws ParseException
{
String str
="2008-08-08 20:08:08";
SimpleDateFormat sdf
=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date
=sdf
.parse(str
);
System
.out
.println(date
);
}
练习实例:
* 程序启动后,要求用户输入自己的生日,格式
:yyyy
-MM
-dd
* 然后经过程序计算,输出到今天为止一共活了多少天
?
* 以及出生
10000天的纪念日是哪天,纪念日格式同上
public static void main(String
[] args
) throws ParseException
{
Scanner scanner
= new Scanner(System
.in
);
System
.out
.println("请输入您的生日:");
String birthStr
= scanner
.nextLine();
SimpleDateFormat sdf
= new SimpleDateFormat(
"yyyy-MM-dd"
);
Date birth
= sdf
.parse(birthStr
);
Date now
= new Date();
long time
= now
.getTime()-birth
.getTime();
time
= time
/1000/60/60/24;
System
.out
.println("恭喜您,已经活了"+time
+"天!请继续保持!");
time
= birth
.getTime()+1000L
*60*60*24*10000;
Date date
= new Date(time
);
String line
= sdf
.format(date
);
System
.out
.println("出生10000天的纪念日为:"+line
);
}
Calendar
* java
.util
.Calendar
;
* 日历类,用于操作时间的API。
* Calendar本身是一个抽象类。
* 常见实现类:GregoranCalendar
, 即:阳历
*
* 可以通过Calendar提供的静态方法:getInstance方法获取一个当前地区时间的实现类,
* 绝大数地区获取的都是阳历。
实例:
public static void main(String
[] args
) {
Calendar calendar
=Calendar
.getInstance();
System
.out
.println(calendar
);
Date date
=calendar
.getTime();
System
.out
.println(date
);
}
Calendar提供了获取指定时间分量对应值的操作
* int get(int filed
)
* 参数为对应的时间分量,返回值为该时间分量所对应的值。
* 而时间分量Calendar提供了大量的常量来表示。
实例:
public static void main(String
[] args
) {
Calendar cal
=Calendar
.getInstance();
int year
=cal
.get(Calendar
.YEAR
);
int month
=cal
.get(Calendar
.MONTH
)+1;
int day
=cal
.get(Calendar
.DATE
);
System
.out
.println(year
+"-"+month
+"-"+day
);
int h
=cal
.get(Calendar
.HOUR_OF_DAY
);
int m
=cal
.get(Calendar
.MINUTE
);
int s
=cal
.get(Calendar
.SECOND
);
System
.out
.println(h
+":"+m
+":"+s
);
int days
=cal
.get(Calendar
.DAY_OF_YEAR
);
System
.out
.println(days
);
int dayw
=cal
.get(Calendar
.DAY_OF_WEEK
);
String
[] data
={"日","一","二","三","四","五","六"};
System
.out
.println(data
[dayw
]);
int countDay
=cal
.getActualMaximum(Calendar
.DAY_OF_YEAR
);
System
.out
.println("今年一共:"+countDay
+"天!");
int conday
=cal
.getActualMaximum(Calendar
.DAY_OF_MONTH
);
System
.out
.println("当月一共:"+conday
+"天!");
}
* void set(int field
,int value
)
* 设置指定时间分量为给定的值
public static void main(String
[] args
) {
Calendar calen
=Calendar
.getInstance();
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.YEAR
, 2008);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.MONTH
,Calendar
.AUGUST
);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.DAY_OF_MONTH
, 8);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.HOUR
, 9);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.MINUTE
, 55);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.SECOND
,20);
System
.out
.println(calen
.getTime());
}
* void add(int field
,int amount
)
* 对指定的时间分量累加指定的值,若给定的值为负数,则是减去
public static void main(String
[] args
) {
Calendar calen
=Calendar
.getInstance();
System
.out
.println(calen
.getTime());
calen
.add(Calendar
.YEAR
, 3);
calen
.add(Calendar
.MONTH
, 2);
calen
.add(Calendar
.DAY_OF_MONTH
, 25);
System
.out
.println(calen
.getTime());
calen
.set(Calendar
.DAY_OF_WEEK
, Calendar
.FRIDAY
);
System
.out
.println(calen
.getTime());
}
*案例:
* 计算商品的促销日期,
* 输入一个商品的生产日期,格式:yyyy
-MM
-dd
* 再输入该商品的的保质期天数。
* 然后经过程序计算输出该商品的促销日期,格式同上
*
* 促销日期计算规则:该商品过期日期前两周的周三
public static void main(String
[] args
) throws ParseException
{
Scanner scan
=new Scanner(System
.in
);
System
.out
.println("请输入商品的生产日期(格式:yyyy-MM-dd):");
String product
=scan
.nextLine();
System
.out
.println("请再次输入商品的保质期:");
int day
=Integer
.parseInt(scan
.nextLine());
SimpleDateFormat sdf
=new SimpleDateFormat("yyyy-MM-dd");
Calendar calen
=Calendar
.getInstance();
Date date
=sdf
.parse(product
);
calen
.setTime(date
);
calen
.add(Calendar
.DAY_OF_MONTH
, day
);
calen
.add(Calendar
.WEEK_OF_MONTH
, -2);
calen
.set(Calendar
.DAY_OF_WEEK
, Calendar
.WEDNESDAY
);
System
.out
.println(calen
.getTime());
}
--------lambda新特性 --------
* lambda表达式
* lambda是JDK1
.8推出的一个特性,让我们可以 以函数式编程
*
* lambda可以更简单的完成匿名内部类的创建。
* 语法规则:
* ([参数列表
])->{
* 方法体
* }
* 使用lambda创建的匿名内部类所属结构必须只能有
1个抽象方法
,否则无法使用。
Runnable r2
=()->{
System
.out
.println("2:HelloWorld!");
};
Runnable r3
=()->System
.out
.println("3:HelloWorld!");
Collections
.sort(list
,(o1
,o2
)-> o1
.length()-o2
.length());
* JDK1
.8之后遍历集合,Map推出了一个方法:forEach
* 该方法可以使用lambda来遍历集合。
* 由于该方法是集合自身的方法进行遍历,那么如果该集合是一个
* 并发安全的集合时,这种遍历方法是可以和其他集合操作进行互斥的。达到并发安全。
*
* 原迭代器方式是不与集合自身方法互斥的,需要自行维护并发安全问题。
public static void main(String
[] args
) {
List
<String> list
=new ArrayList<String>();
list
.add("苍老师");
list
.add("饭桶");
list
.add("苍山有井");
list
.add("苍山有井,水为空");
System
.out
.println(list
);
list
.forEach((e
)->System
.out
.println(e
));
list
.forEach(str
->System
.out
.println(str
));
Map
<String, Integer> map
=new HashMap<String, Integer>();
map
.put("语文", 98);
map
.put("数学", 97);
map
.put("英语", 96);
map
.put("物理", 95);
map
.put("化学", 94);
map
.forEach((k
,v
)->System
.out
.println(k
+":"+v
));
}
--------java注解 --------
注解类:ATest
.jsva
@Retention(RetentionPolicy
.RUNTIME
)
public @
interface ATest {
public String
value();
}
测试类:B
.java
public class B {
@ATest(value
= "Hello")
public void m1(){
System
.out
.println("B's m1()...");
}
public void m2(){
System
.out
.println("B's m2()...");
}
@ATest("World")
public void hello(){
System
.out
.println("B's hello()...");
}
}
测试注解读取属性类:TestCase
public static void main(String
[] args
) throws Exception
{
Class
<?> cls
=Class
.forName("reflect.B");
Object obj
=cls
.newInstance();
Method
[] methods
=cls
.getDeclaredMethods();
for(Method mh
:methods
){
ATest test
=mh
.getDeclaredAnnotation(ATest
.class);
System
.out
.println(test
);
if(test
!=null
){
mh
.invoke(obj
);
String v1
=test
.value();
System
.out
.println("value():"+v1
);
}
}
}
--------解析XML配置文件--------
使用DOM4J解析XML文档
*案例:
public class ParseXmlDemo {
public static void main(String
[] args
) {
List
<Emp> list
= new ArrayList<Emp>();
try {
SAXReader reader
= new SAXReader();
Document doc
= reader
.read(new File("emplist.xml"));
Element root
= doc
.getRootElement();
System
.out
.println("root:"+root
.getName());
List
<Element> empList
= root
.elements("emp");
System
.out
.println("<emp>标签个数:"+empList
.size());
for(Element empEle
: empList
) {
Element nameEle
= empEle
.element("name");
String name
= nameEle
.getText();
System
.out
.println(name
);
int age
= Integer
.parseInt(empEle
.element("age").getText());
String gender
= empEle
.elementText("gender");
int salary
= Integer
.parseInt(empEle
.elementText("salary"));
int id
= Integer
.parseInt(empEle
.attributeValue("id"));
Emp emp
= new Emp(id
, name
, age
, gender
, salary
);
list
.add(emp
);
}
System
.out
.println("解析完毕!");
for(Emp emp
: list
) {
System
.out
.println(emp
);
}
} catch (Exception e
) {
e
.printStackTrace();
}
}
}
使用DOM4J生成一个XML文档
*案例:
public class WriteXmlDemo {
public static void main(String
[] args
) {
List
<Emp> list
= new ArrayList<Emp>();
list
.add(new Emp(1, "张三", 22, "男", 5000));
list
.add(new Emp(2, "李四", 23, "女", 6000));
list
.add(new Emp(3, "王五", 24, "男", 7000));
list
.add(new Emp(4, "赵六", 25, "女", 8000));
list
.add(new Emp(5, "钱七", 26, "男", 9000));
try {
Document doc
= DocumentHelper
.createDocument();
Element root
= doc
.addElement("list");
for(Emp emp
: list
) {
Element empEle
= root
.addElement("emp");
Element nameEle
= empEle
.addElement("name");
nameEle
.addText(emp
.getName());
Element ageEle
= empEle
.addElement("age");
ageEle
.addText(emp
.getAge()+"");
Element genderEle
= empEle
.addElement("gender");
genderEle
.addText(emp
.getGender());
Element salaryEle
= empEle
.addElement("salary");
salaryEle
.addText(emp
.getSalary()+"");
empEle
.addAttribute("id", emp
.getId()+"");
}
XMLWriter writer
= new XMLWriter(
new FileOutputStream("myemp.xml"),
OutputFormat
.createPrettyPrint()
);
writer
.write(doc
);
System
.out
.println("写出完毕!");
writer
.close();
} catch (Exception e
) {
e
.printStackTrace();
}
}
}
解析XML文件,结合反射
*案例:
public void init() throws ServletException
{
List
<Object> beans
=new ArrayList<Object>();
SAXReader reader
=new SAXReader();
InputStream in
= getClass().getClassLoader().getResourceAsStream("smartmvc.xml");
try {
Document doc
=reader
.read(in
);
Element root
=doc
.getRootElement();
List
<Element> elements
=root
.elements();
for(Element ele
:elements
){
String className
=ele
.attributeValue("class");
Object bean
=Class
.forName(className
).newInstance();
beans
.add(bean
);
}
System
.out
.println(beans
);
} catch (Exception e
) {
e
.printStackTrace();
throw new ServletException(e
);
}
}
使用Jsoup解析XML文档
jsoup 是一款Java 的HTML解析器,可直接解析某个URL地址、HTML文本内容。
它提供了一套非常省力的API,可通过DOM,CSS以及类似于jQuery的操作方法来取出和操作数据。
1、导包
2、获取Document对象
3、获取对应的标签Element对象
4、获取数据
"快速入门"
public static void main(String
[] args
) throws IOException
{
String path
=JsoupXML
.class.getClassLoader().getResource("student.xml").getPath();
Document doc
=Jsoup
.parse(new File(path
), "UTF-8");
Elements eles
=doc
.getElementsByTag("name");
Elements eles2
=doc
.getElementsByTag("student");
System
.out
.println(eles
.size());
Element ele
=eles
.get(0);
String text
=ele
.text();
Element ele2
=eles2
.get(0);
String attr
=ele2
.attr("number");
System
.out
.println("name:"+text
);
}
对象的使用
1、Jsoup
:工具类,可以解析html或xml文档,返回Document
*parse
:解析html或xml文档,返回Document对象。
Jsoup
.parse(File in
,String charsetName
):解析xml或html文件
Jsoup
.parse(String html
):解析xml或html字符串
Jsoup
.parse(url
, timeoutMillis
)
URL url
=new URL("https://www.baidu.com/");
Document doc
=Jsoup
.parse(url
, 10000);
System
.out
.println(doc
);
2、Document:文档对象。代表内存中的dom树
*获取Element对象
Element
getElementById(String id
):根据id属性值来获取唯一的Element对象。
Elements
getElementsByTag(String tagName
) :根据标签名称获取元素对象集合
Elements
getElementsByAttribute(String key
):根据属性名称获取元素对象集合
Elements
getElementsByAttributeValue(String key
, String value
)
根据对应的属性名和属性值获取元素对象集合
3、Elements:元素Element对象的集合。可以当做ArrayList
<Element>来使用
4、Element:元素对象,对应的标签对象
1、获取子元素对象
Element
getElementById(String id
):根据id属性值来获取唯一的Element对象。
Elements
getElementsByTag(String tagName
) :根据标签名称获取元素对象集合
Elements
getElementsByAttribute(String key
):根据属性名称获取元素对象集合
Elements
getElementsByAttributeValue(String key
, String value
)
根据对应的属性名和属性值获取元素对象集合
2、获取属性值
String
attr(String attributeKey
):根据属性名称获取属性的值
3、获取文本内容
String
text():获取所有子标签的纯文本内容
String
html():获取子标签体的标签和内容
5、Node:节点对象
*是Document和Element的父类。
快捷查询方式
1、selector:选择器
*使用方法:Elements
select(String cssQuery
)
Elements eles
=doc
.select("name");
System
.out
.println(eles
);
System
.out
.println("1-----------------------------");
Elements ele1
=doc
.select("#itcast");
System
.out
.println(ele1
);
System
.out
.println("2-----------------------------");
Elements ele2
=doc
.select("student[number='001'] age");
System
.out
.println(ele2
);
2、XPath
:
XPath即为XML路径语言(XML Path Language),它是一种用来确定XML文档中某部分位置的语言。
*使用Jsoup的XPath需要额外导入jar包
如果你能看里,说明已经看完这篇技术文档,祝你:基础扎实、技术飞升、工资翻倍!别忘了点个赞,支持一下 。