1.什么是JDK API:
1).JDK中包含大量的API类库,所谓API就是一些已写好,可提供直接调用的功能(这些功能以类的形式封装)
2). JDK API 包含的类库功能强大,经常使用的又:字符串操作,集合操作,文件操作,输入输出造成,网络操作,多线程等等。
2.JDK包结构
为了便于使用和维护,JDK类库按照包结构划分,不同功能的类划分在不同的包中;
经常使用的包如下:
包 功能
java.lang java程序的基础类,如字符串,多线程等,不需要import,可以直接使用
java.util 常用工具类,如集合,随机数产生器,日历,时钟等
java.io 文件操作,输入/输出操作
java.net 网络操作
java.math 数学运算相关操作
java.security 安全相关操作
java.sql 数据库访问
java.text 处理文字,日期,数字,信息的格式
3.文档注释
3.1) 以/开头,以/结束;
3.2)加在类和方法的开头,用于说明作者,时间,版本,要实现功能的纤细描述等信息
3.3)通过javadoc工具,可以轻松的讲次注释转换为HTML文档说明,学习者和程序员主要通过文档了解API的功能
4.文档注释规范:
/*
*类功能说明…
*@author Lee Boynton (作者)
*@version 1.4(版本)
*@see java.lang.StringBuffer(参见)
*@since JDK1.0 (始于JDK版本)
*@param charsetName(参数说明)
*@return The resultant byte array (返回值说明)
@throws UnsupporteE…(异常抛出说明)
/
5.生成javadoc文档
5.1)为带骂添加文档注释/ */
5.2)使用eclipse生成文档注释,首先点击file-Export-java–Javadoc-Next,然后选择你要生成的Javadoc的包,以及生成的Javadoc所存路径(Use Standard doclet),默认生成当前工程目录,点击Finish 即可。
StringBuffer 和 StringBuilder 的区别
StringBuffer是线程安全的,同步处理的,性能稍慢
StringBuilder是非线程安全的,并法处理的,性能稍快
———————————————————————————————————
**API**
字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值。
java字符串中任何一个字符对应16位(两个字节)的定长Unicode编码。
/**
* int length()
* 返回当前字符串长度(字符个数)
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "我爱java";
System.out.println("len:"+str.length());
}}
/**
* int indexOf(String str)
* 返回给定字符串在当前字符串中的位置,若当
* 前字符串不包含该内容则返回值为-1
* @author Mr.Cui
*/
public static void main(String[] args) {
// 0123456789012345
String str = "thinking in java";
int index = str.indexOf("in");
System.out.println("index:"+index);
//可以从指定位置开始查找
index = str.indexOf("in", 3);
System.out.println("index:"+index);
//查找最后一次出现的位置
index = str.lastIndexOf("in");
System.out.println("index:"+index);
}}
/**
* String substring(int start,int end)
* 截取指定范围内的字符串。两个参数为开始到
* 结束的下标。
* 注:java api有一个特点,通常用两个数字表示
* 范围时都是"含头不含尾"的。
* @author Mr.Cui
*/
public static void main(String[] args) {
// 0123456789012
String host = "www.baidu.com";
String sub = host.substring(4, 9);
System.out.println(sub);
//一个参数为截取到末尾
sub = host.substring(4);
System.out.println(sub);
}}
/**
* char charAt(int index)
* 获取当前字符串中指定位置处对应的字符
* @author Mr.Cui
*/
public static void main(String[] args) {
// 0123456789012345
String str = "thinking in java";
char c = str.charAt(9);
System.out.println(c);
/*
* 判断回文
* 上海自来水来自海上
*/
str = "上海自来水自来海上";
for(int i=0;i<str.length()/2;i++) {
char c1 = str.charAt(i);
char c2 = str.charAt(str.length()-1-i);
if(c1!=c2) {
System.out.print("不");
break;
}
}
System.out.println("是回文");
}}
/**
* String支持正则表达式方法之一:
* boolean matches(String regex)
* 用给定的正则表达式验证当前字符串是否符合
* 其格式要求。
* @author Mr.Cui
*/
public static void main(String[] args) {
String email = "[email protected]";
/*
* 验证email格式的正则表达式
* \w+@\w+(\.[a-zA-Z]+)+
*/
String regex = "\\w+@\\w+(\\.[a-zA-Z]+)+";
/*
* 注意:matches方法指定的正则表达式就算不
* 指定边界匹配符,也是做全匹配验证的。
*/
boolean match = email.matches(regex);
if(match) {
System.out.println("是邮箱");
}else {
System.out.println("不是邮箱");
} }}
/**
* String replaceAll(String regex,String str)
* 将当前字符串中符合正则表达式要求的部分替换
* 为给定内容
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "abc123def456ghi789jkl";
/*
* 将数字部分替换为"#NUMBER#"
*/
String regex = "[0-9]+";
str = str.replaceAll(regex, "#NUMBER#");
System.out.println(str);
}}
import java.util.Arrays;
/**
* String[] split(String regex)
* 使用给定的正则表达式来拆分当前字符串。
* 并将拆分后的内容以字符串数组形式返回。
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "abc123def456jhi789klm";
String[] array = str.split( "[0-9]+");//0-9全部去除
System.out.println(array.length);
System.out.println(Arrays.toString(array));
}}
/**
* boolean startsWith(String str)开始
* boolean endsWith(String str) 结尾
* 判断当前字符串是否是以给定字符串开始或
* 结尾的。
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "thinking in java";
//开始
boolean starts = str.startsWith("thi");
System.out.println("starts:"+starts);
//结尾
boolean ends = str.endsWith("va");
System.out.println("ends:"+ends);
}}
/**
* StringBuilder专门用来修改字符串内容的API.
* String由于其优化设计导致的问题就是不能频繁
* 修改(每次都创建新对象)
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "努力学习java";
//默认表示空字符串
//StringBuilder builder= new StringBuilder();
StringBuilder builder
= new StringBuilder(str);
/*
* 拼接字符串append()
*/
builder.append(",为了找个好工作!");
/*
* StringBuilder的toString方法用来
* 获取其内部表示的字符串内容toString
*/
str = builder.toString();
System.out.println(str);
/*
* 努力学习java,为了找个好工作!
* 努力学习java,就是为了改变世界!
*定向改变字符内容replace()
* replace()
*/
builder.replace(9, 16, "就是为了改变世界");
System.out.println(builder);
/*
* 努力学习java,就是为了改变世界!
* ,就是为了改变世界!
*定向删除字符内容delete()
* delete()
*/
builder.delete(0, 8);
System.out.println(builder.toString());
/*
* ,就是为了改变世界!
* 活着,就是为了改变世界!
*指定位置添加内容 insert()
* insert()
*/
builder.insert(0,"活着");
System.out.println(builder.toString());
}}
/**
* StringBuilder修改性能
* @author Mr.Cui
*/
public static void main(String[] args) {
StringBuilder builder = new StringBuilder("a");
for(int i=0;i<10000000;i++) {
builder.append("a");
}
System.out.println("执行完毕!");
}}
/**
* 字符串频繁修改带来的性能损耗
*String是不变对象,每次内容更改都是创建新对象
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "a";
for(int i=0;i<10000000;i++) {
str += "a";
//系统需要很长很长时间才能运行出结果,a结果有无数个
}
System.out.println("执行完毕!");
}}
/*StringBuffer 和 StringBuilder 的区别
StringBuffer是线程安全的,同步处理的,性能稍慢
StringBuilder是非线程安全的,兵法处理的,性能稍快*/
/**
* String是不变对象,JVM对其做了一个优化,在内存
* 中开辟了一段区域作为常量池,凡是通过"字面量"形
* 式创建的字符串对象都会缓存并重用。因为会重用
* 对象,所以该对象内容不可变。
* @author Mr.Cui
*/
public static void main(String[] args) {
String s1 = "123abc";
//s2,s3重用s1创建的字符串对象
String s2 = "123abc";
String s3 = "123abc";
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
//修改内容会创建并引用新对象
s1 = s1+"!";
System.out.println("s1:"+s1);
//s2,s3不受影响
System.out.println("s2:"+s2);
//new则一定创建新对象
String s4 = new String("123abc");
System.out.println("s4:"+s4);
System.out.println(s2==s4);//false
/*
* 编译器有一个优化措施,当编译源代码
* 时发现一个计算表达式所有参数都是字面
* 量时,会直接进行计算,并将结果编译到
* class文件中。
* 所以,下面的代码在class文件中为:
* String s5 = "123abc";
*/
String s5 = "123"+"abc";
System.out.println("s5:"+s5);
System.out.println(s2==s5);//true
/*
* 计算表达式一方为变量,那么会在运行期
* 拼接,那么会创建新对象
*/
String s = "123";
String s6 = s + "abc";
System.out.println("s6:"+s6);
System.out.println(s2==s6);//false
} }
/**
* String substring(int start,int end)
* 完成方法,获取给定地址中的域名
* @author Mr.Cui
*/
public static void main(String[] args) {
String url = "www.sohu.com";
String name = getHostName(url);
System.out.println(name);//sohu
url = "http://www.tedu.com.cn";
name = getHostName(url);
System.out.println(name);//tedu
}
public static String getHostName(String url) {
int start = url.indexOf(".")+1;
int end = url.indexOf(".",start);
return url.substring(start, end);
}}
/**
* 要求用户从控制台输入一个email地址,然后获取该email的用户名(@之前的内容)
* @author Mr.Cui
*/
import java.util.Scanner;
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
System.out.println("请输入email");
String num = scan.next();
/**
* int indexOf(String str)
* 返回给定字符串在当前字符串中的位置,若当
* 前字符串不包含该内容则返回值为-1
* @author Mr.Cui
*/
int index = num.indexOf("@");
/**
* String substring(int start,int end)
* 截取指定范围内的字符串。两个参数为开始到
* 结束的下标。
* 注:java api有一个特点,通常用两个数字表示
* 范围时都是"含头不含尾"的。
* @author Mr.Cui
*/
String ss = num.substring(0, index);
System.out.println(ss);
import java.util.Date;
/**
* String imageRename(name)
* 图片重命名
* @author Mr.Cui
*/
public static void main(String[] args) {
String imageName = "abc.jpg";
imageName = imageRename(imageName);
System.out.println(imageName);
}
public static String imageRename(String imageName) {
//按照"."拆分
String[] data = imageName.split("\\.");
imageName
= System.currentTimeMillis()+"."+data[1];
return imageName;
}}
/**
*replaceAll(indet,String "**")
* 和谐用语
* @author Mr.Cui
*/
public static void main(String[] args) {
String regex = "(wqnmlgdsb|mmp|nc|mdzz|cnm|djb)";
String message = "wqnmlgdsb!你怎么这么nc!cnm,你个djb!";
message = message.replaceAll(regex, "***");
System.out.println(message);
}}
/**
* String toUpperCase()//大写
* String toLowerCase()//小写
* 将当前字符串中的英文部分转换为全大写或者全小写
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "我爱Java";
//大写
String upper = str.toUpperCase();
System.out.println("upper:"+upper);
//小写
String lower = str.toLowerCase();
System.out.println("lower:"+lower);
}}
/**
* String trim()
* 去除一个字符串两边的空白字符
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = " hello ";
System.out.println(str);
String trim = str.trim();
System.out.println(trim);
}}
/**
* String提供了一组重载的静态方法:valueOf
* 可以将给定的内容转换为字符串
* @author Mr.Cui
*/
public static void main(String[] args) {
int d = 1;
String str = String.valueOf(d);
System.out.println(str);
double dou = 1.1;
str = String.valueOf(dou);
System.out.println(str);
str = d+"";
}}
/**
* 使用当前类测试重写Object相关方法
* @author Mr.Cui
*/
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
/**
* toString方法会被很多API调用。所以当我们
* 定义一个类时,很常见的操作就是重写这个
* 方法。
* 该方法的意义是将当前对象转换为一个字符串
* 形式。该字符串内容格式没有严格的要求。
* 原则为包含这个对象的相关属性信息。
*/
public String toString() {
//(1,2)
return "("+x+","+y+")";
}
/**
* equals的作用是比较当前对象与参数对象
* 的内容是否一致。
*/
public boolean equals(Object obj) {
if(obj==null) {
return false;
}
if(this==obj) {
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x==p.x&&this.y==p.y;
}
return false;
}}
/**
* 测试Point重写的Object相关方法
* @author Mr.Cui
*/
public static void main(String[] args) {
Point p = new Point(1,2);
/*
* 通常我们定义的类如果需要使用到
* toString方法时,就应当重写这个
* 方法,Object提供的输出的是该对象
* 的句柄,没有什么实际意义
*/
String str = p.toString();
System.out.println(str);
/*
* System.out.println(Object obj)
* 该方法会将给定对象的toString方法
* 返回的字符串输出到控制台
*/
System.out.println(p);
Point p2 = new Point(1,2);
System.out.println(p==p2);//false
/*
* 我们定义的类如果使用equals,就应当
* 重写这个方法。Object提供的equals方法
* 本身内部就是用“==”进行比较的,没有
* 实际意义。
* 而java API提供的类,toString,equals
* 方法都妥善进行了重写。
*/
System.out.println(p.equals(p2));//true
}}
/**
* JDK1.5版本推出时推出了一个特性:
* 自动拆装箱
* 该特性是编译器认可的,当我们在基本类型和
* 其对应的引用类型之间互相赋值时,编译器会
* 自动补全代码在两者之间进行转换。
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 触发了编译器的自动拆箱特性:
* 编译器会补全代码,将包装类转换为
* 基本类型。
* 下面的代码会被编译器补充代码为:
* int d = new Integer(1).intValue();
*/
int d = new Integer(1);
/*
* 触发自动装箱特性,编译器会补充代码
* Integer i = Integer.valueOf(d);
*/
Integer i = d;
}}
/**
* 包装类
* 包装类是为了解决基本类型不能直接参与面向
* 对象开发的问题。
* 其中6个数字类型的包装类继承自Number类。
* java.lang.Number是一个抽象类,定义了几个
* 抽象方法,要求数字类型的包装类可以将其表示
* 的数字以任意数字类型返回。
* @author Mr.Cui
*/
public class IntegerDemo1 {
public static void main(String[] args) {
int d = 128;
//转换为包装类
//Integer i1 = new Integer(d);
//Integer i2 = new Integer(d);
//推荐用valueOf转换为包装类
Integer i1 = Integer.valueOf(d);
Integer i2 = Integer.valueOf(d);
System.out.println(i1==i2);
System.out.println(i1.equals(i2));
/*
* 包装类转换为基本类型
*/
d = i1.intValue();
System.out.println(d);
double dou = i1.doubleValue();
System.out.println(dou);
byte b = i1.byteValue();
System.out.println(b);
/*
* 数字类型的包装类都定义了两个常量
* MAX_VALUE 最大值
* MIN_VALUE 最小值
* 用于表示该包装类对应的基本类型的
* 取值范围
*/
int imax = Integer.MAX_VALUE;
System.out.println(imax);
int imin = Integer.MIN_VALUE;
System.out.println(imin);
long lmax = Long.MAX_VALUE;
System.out.println(lmax);
}}
/**
* 包装类都提供了一个静态方法:
* parseXXX(String str)
* 可以将字符串解析为对应的基本类型,但是需要
* 注意,该字符串必须能够正确描述该基本类型可
* 以保存的值,否则会抛出异常。
* @author Mr.Cui
*/
public static void main(String[] args) {
String str = "123";
int d = Integer.parseInt(str);
System.out.println(d);
double dou = Double.parseDouble(str);
System.out.println(dou);
}}
/**
* 读取文件数据
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 读取当前目录中raf.dat文件内容
*/
RandomAccessFile raf
= new RandomAccessFile("raf.dat","r");
/*
* int read()
* 读取一个字节,并以int形式返回。
* 若返回值为-1则表示读取到了文件末尾。
* 00000000 00000000 00000000 00000001
*/
int d = raf.read();
System.out.println(d);
d = raf.read();
System.out.println(d);//-1
raf.close();
}}
/**
* 若希望提高读写效率,可以通过提高每次实际读写
* 的数据量,减少实际发生的读写操作来做到。
* 单字节读写:随机读写
* 一组字节读写:块读写
* 机械硬盘(磁盘)的块读写效率还是比较好的。但是
* 随机读写效率极差。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
RandomAccessFile src
= new RandomAccessFile("nox.exe","r");
RandomAccessFile desc
= new RandomAccessFile("nox_cp.exe","rw");
/*
* RAF提供的块读写操作的方法:
* int read(byte[] data)
* 一次性读取给定的字节数组长度的字节
* 量并存入到该数组中。返回值为实际
* 读取到的字节量,若返回值为-1,表示
* 本次读取是文件末尾(没读到任何字节)
*
* void write(byte[] data)
* 一次性写出给定字节数组中的所有字节
*
* void write(byte[] data,int start,int len)
* 一次性写出给定字节数组中从start处开始的连续
* len个字节
*/
//记录每次实际读取到的字节量
int len = -1;
//每次要求读取的字节量
//10kb
byte[] data = new byte[1024*10];
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();
}}
/**
* java.io.RandomAccessFile
* RAF是专门用来读写文件数据的API。其基于指针
* 对文件数据进行读写操作,可以灵活的编辑文件
* 数据内容。
* 创建RAF时可以指定对该文件的权限,常用的有
* 两种:
* r:只读模式
* rw:读写模式
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 对当前目录中的raf.dat文件读写
* RAF支持两种常用构造方法:
* RandomAccessFile(File file,String mode)
* RandomAccessFile(String path,String mode)
*
* 注:相对路径中"./"是可以忽略不写的,因为
* 默认就是从当前目录开始。
*
* RAF创建时含有写权限的情况下,当指定的文件
* 不存在时会自动将其创建出来。
*/
RandomAccessFile raf
= new RandomAccessFile("raf.dat","rw");
/*
* void write(int d)
* 向文件中写入1字节,写的是给定int值
* 对应2进制的“低八位”
* vvvvvvvv
* 00000000 00000000 00000000 00000001
* 11111111 11111111 11111111 11111111
*
*/
raf.write(1);
System.out.println("写出完毕!");
raf.close();
}}
/**
* 完成方法,实现删除给定File所表示的文件或目录
* @author Mr.Cui
*/
public static void main(String[] args) {
File dir = new File("./a");
delete(dir);
}
/**
* 文件直接删除,目录的话要先清空该目录
* 然后再删除
* @param f
*/
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();
}}
/**
* 创建一个多级目录
* @author ta
*/
public static void main(String[] args) {
/*
* 在当前目录下创建:
* a/b/c/d/e/f目录
*/
File dir = new File("./a/b/c/d/e/f");
if(!dir.exists()) {
/*
* mkdir创建目录要求父目录必须存在
* mkdirs会将不存在的父目录一同的
* 创建出来
*/
dir.mkdirs();
System.out.println("创建完毕!");
}else {
System.out.println("目录已存在!");
}}}
/**
* 创建一个目录
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 在当前目录中创建一个名为demo的目录
*/
File dir = new File("./demo");
if(!dir.exists()) {
dir.mkdir();
System.out.println("目录已创建");
}else {
System.out.println("目录已存在");
}}}
/**
* ListFiles提供了一个重载的方法,可以指定
* 一个文件过滤器(FileFilter),然后将满足该
* 过滤器要求的子项返回。
* @author ta
*/
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());
}}}
/**
* 获取一个目录中的所有子项
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 获取当前目录中的所有子项
*/
File dir = new File(".");
/*
* boolean isFile()
* boolean isDirectory()
* 判断当前File对象表示的是一个文件
* 还是一个目录
*/
if(dir.isDirectory()) {
/*
* File[] listFiles()
* 该方法会将当前File表示的目录中所有
* 子项返回.
*/
File[] subs = dir.listFiles();
for(int i=0;i<subs.length;i++) {
File sub = subs[i];
System.out.println(sub.getName());
}}}}
/**
* java.io.File
* File的每一个实例用于表示硬盘上的一个文件或
* 目录。
* 使用File可以:
* 1:访问其表示的文件或目录的属性信息(名字,大
* 小,访问权限等信息)
* 2:操作文件或目录(创建,删除)
* 3:访问目录子项
* 但是不能访问文件数据。
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 访问当前项目目录下的test.txt文件
*
* 创建File时,指定的路径通常使用相对
* 路径,好处在于:可以跨平台。
* 相对路径到底相对哪里,要看程序的
* 运行环境指定的位置。
* 在eclipse中运行java程序时,指定的
* 相对路径中"当前目录"是当前程序所在
* 的项目目录,这里就是JSD1807_SE这个
* 目录
*/
File file = new File("./test.txt");
//获取文件名
String name = file.getName();
System.out.println("name:"+name);
//获取文件大小(字节量)
long length = file.length();
System.out.println("length:"+length);
boolean cw = file.canWrite();//可写
boolean cr = file.canRead();//可读
System.out.println("可写:"+cw);
System.out.println("可读:"+cr);
boolean ih = file.isHidden();//隐藏
System.out.println("隐藏:"+ih);
}}
/**
* 删除一个文件
* @author ta
*/
public static void main(String[] args) {
/*
* 将当前目录下的demo.txt文件删除
*/
File file = new File("./demo.txt");
if(file.exists()) {
file.delete();
System.out.println("文件已删除");
}else {
System.out.println("文件不存在");
}}}
/**
* 删除目录
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 删除当前目录下的demo目录
*/
File dir = new File("./demo");
if(dir.exists()) {
/*
* 删除目录要求该目录必须是一个
* 空目录。
*/
dir.delete();
System.out.println("删除完毕!");
}else {
System.out.println("目录不存在!");
}}}
/**
* 使用File创建一个文件
* @author Mr.Cui
*/
public class CreateNewFileDemo {
public static void main(String[] args) throws IOException {
/*
* 在当前目录下创建一个名为:demo.txt
* 的文件
*/
File file = new File("./demo.txt");
if(!file.exists()) {
file.createNewFile();
System.out.println("文件已创建");
}else {
System.out.println("文件已存在");
}}}
/**
* 写入字符串操作
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
RandomAccessFile raf
= new RandomAccessFile("raf.txt","rw");
String line = "大家好,我是渣渣辉。";
/*
* String提供了转换为2进制的方法:
* byte[] getBytes();
*/
//byte[] data = line.getBytes();
//可以指定字符集进行转换(推荐这样的用法)
byte[] data = line.getBytes("UTF-8");
raf.write(data);
System.out.println("写出完毕");
raf.close();
}}
/**
* 读取字符串
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 将raf.txt文件中的字符读取出来
*/
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读写基本类型数据,以及RAF的指针操作
*//创建文件 rw,读写文件r
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
RandomAccessFile raf
= new RandomAccessFile("raf.dat","rw");
long pos = raf.getFilePointer();
System.out.println("pos:"+pos);
//写入一个int最大值到文件中
int max = Integer.MAX_VALUE;
/*
* int最大值的2进制形式:
* vvvvvvvv
* 01111111 11111111 11111111 11111111
*
* max>>>24 v这里开始溢出了
* 00000000 00000000 00000000 01111111 11111111 11111111 11111111
*/
raf.write(max>>>24);
System.out.println("pos:"+raf.getFilePointer());
raf.write(max>>>16);
raf.write(max>>>8);
raf.write(max);
System.out.println("pos:"+raf.getFilePointer());
/*
* void writeInt(int d)
* 连续写出4个字节,将给定的int值写出。
* 等同上面4次write方法。
*/
raf.writeInt(max);
System.out.println("pos:"+raf.getFilePointer());
raf.writeLong(123L);
System.out.println("pos:"+raf.getFilePointer());
raf.writeDouble(123.123);
System.out.println("pos:"+raf.getFilePointer());
System.out.println("写出完毕!");
//写完后指针现在在文件末尾
//移动指针位置
raf.seek(0);//移动到文件开始位置
System.out.println("pos:"+raf.getFilePointer());
//连续读取4字节还原int值
int d = raf.readInt();
System.out.println(d);
System.out.println("pos:"+raf.getFilePointer());
//读取long
raf.seek(8);
System.out.println("pos:"+raf.getFilePointer());
long l = raf.readLong();
System.out.println(l);//123
System.out.println("pos:"+raf.getFilePointer());
double dou = raf.readDouble();
System.out.println(dou);//123.123
System.out.println("pos:"+raf.getFilePointer());
raf.close();
}}
/**
* 完成用户注册功能
*
* 程序开始后,要求用户输入:
* 用户名,密码,昵称,年龄
*
* 将该记录写入到user.dat文件中。
* 其中用户名,密码,昵称为字符串。年龄为
* 一个int值。
*
* 每条记录占用100字节,其中:用户名,密码,
* 昵称为字符串,各占32字节,年龄为int占用
* 4字节。
*
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
System.out.println("欢迎注册");
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入密码:");
String password = scanner.nextLine();
System.out.println("请输入昵称:");
String nickname = scanner.nextLine();
System.out.println("请输入年龄:");
int age = Integer.parseInt(scanner.nextLine());//字符串转为整型
System.out.println(username+","+password+","+nickname+","+age);
RandomAccessFile raf
= new RandomAccessFile("user.dat","rw");
//现将指针移动到文件末尾
raf.seek(raf.length());
//写用户名
//1先将用户名转成对应的一组字节
byte[] data = username.getBytes("UTF-8");
//2将该数组扩容为32字节
data = Arrays.copyOf(data, 32);
//3将该字节数组一次性写入文件
raf.write(data);
//写密码
data = password.getBytes("UTF-8");
data = Arrays.copyOf(data, 32);
raf.write(data);
//写昵称
data = nickname.getBytes("UTF-8");
data = Arrays.copyOf(data, 32);
raf.write(data);
//写年龄
raf.writeInt(age);
System.out.println("注册完毕!");
raf.close();
}}
/**
* 修改昵称
*
* 程序启动后,要求用户输入要修改昵称的用户名
* 以及新的昵称。然后将该用户昵称进行修改操作
* 若输入的用户名不存在,则提示"无此用户"。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 1:获取用户输入的用户名及新昵称
* 2:使用RAF打开user.dat文件
* 3:循环读取每条记录
* 3.1:将指针移动到该条记录用户名
* 的位置(i*100)
* 3.2:读取32字节,将用户名读取出来
* 3.3:判断该用户是否为用户输入的用户
* 3.4:若是此人,则移动指针到该条
* 记录昵称位置,将新昵称以32字节
* 写入该位置,覆盖原昵称完成修改
* 并停止循环操作。
* 3.5:若不是此人则进入下次循环
*
* 可以添加一个开关,当修改过昵称后,改变
* 其值,最终在循环完毕后,根据开关的值判定
* 是否有修改信息来输出"无此用户"
*
*/
Scanner scanner = new Scanner(System.in);
System.out.println("请输入用户名:");
String username = scanner.nextLine();
System.out.println("请输入新的昵称:");
String nickname = scanner.nextLine();
RandomAccessFile raf
= new RandomAccessFile("user.dat","rw");
//开关,表示是否有修改过信息
boolean update = false;
for(int i=0;i<raf.length()/100;i++) {
//先将指针移动到该条记录的开始位置
raf.seek(i*100);
//读取用户名
byte[] data = new byte[32];
raf.read(data);
String name = new String(data,"UTF-8").trim();
if(name.equals(username)) {
//修改昵称
//1先移动指针到昵称的位置
raf.seek(i*100+64);
//2重新写昵称32字节
data = nickname.getBytes("UTF-8");
data = Arrays.copyOf(data, 32);
raf.write(data);
System.out.println("修改完毕!");
update = true;
break;
}
}
if(!update) {
System.out.println("无此用户!");
}
raf.close();
}}
/**
* 显示所有注册用户信息
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
RandomAccessFile raf
= new RandomAccessFile("user.dat","r");
/*
* 循环读取若干个100字节
*/
for(int i=0;i<raf.length()/100;i++) {
//读用户名
//1先读取32字节
byte[] data = new byte[32];
raf.read(data);
//2将字节数组转换为字符串
String username = new String(data,"UTF-8").trim();
//读取密码
raf.read(data);
String password = new String(data,"UTF-8").trim();
//读昵称
raf.read(data);
String nickname = new String(data,"UTF-8").trim();
//读年龄
int age = raf.readInt();
System.out.println(username+","+password+","+nickname+","+age);
}
raf.close();
}}
/**
* java IO(input,output) 输入与输出
* IO是我们的程序与外界交换数据的方式。
* java提供了一种统一的标准的方式与外界交换
* 数据。
*
* java将流按照功能划分为读和写,并用不同的方
* 向来表示
* 其中输入流(外界到程序的方向)用于读取数据
* 输出流用于写出数据。
*
* java将流划分为两大类:节点流,处理流
* 节点流:也称为低级流,是实际链接程序与数据源
* 的"管道",负责实际搬运数据。读写一定是建立在
* 节点流的基础上进行的。
*
* 处理流:也称为高级流,不能独立存在,必须链接
* 在其他流上,目的是当数据流经当前流时对这些
* 数据做某些处理,这样可以简化我们对数据的
* 操作。
*
* 实际应用中,我们是链接若干高级流,并最终链接
* 低级流,通过低级流读写数据,通过高级流对读写
* 的数据进行某些加工处理,完成一个复杂的读写
* 操作。这个过程称为"流链接"。这也是学习IO的
* 精髓所在。
*
* 文件流
* 文件流是一对低级流,用于读写文件。就功能而言
* 它们与RandomAccessFile一致。但是底层的读写
* 方式有本质区别。
* RAF是基于指针进行随机读写的,可任意读写文件指定
* 位置的数据。可以做到对文件部分数据的编辑操作。
*
* 流是顺序读写方式,所以不能做到任意读写指定
* 位置数据,对此也无法做到对文件数据进行编辑的
* 操作。但是配合高级流,可以更轻松的读写数据。
*
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 使用文件流向文件中写出字节
*
* FileOutputStream常用构造方法:
* FileOutputStream(String path)
* FileOutputStream(File file)
* 以上两种方式创建时,默认为覆盖写操
* 作,即:若创建时发现该文件已存在,会
* 先将该文件所有数据清除。然后将通过
* 当前流写出的内容作为该文件数据。
*
*
* FileOutputStream(String path,boolean append)
* FileOutputStream(File file,boolean append)
* 追加写模式,即:若指定的文件存在,那么数据全
* 保留,通过该流写出的数据会被追加到文件最后
*
*/
FileOutputStream fos
= new FileOutputStream("fos.txt",true);
String line = "我们一起学猫叫,一起喵喵喵喵喵~";
byte[] data = line.getBytes("UTF-8");
fos.write(data);
System.out.println("写出完毕!");
fos.close();
}}
/**
* 使用文件输入流读取文件数据
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileInputStream fis
= new FileInputStream("fos.txt");
byte[] data = new byte[200];
int len = fis.read(data);
System.out.println("实际读取了:"+len+"个字节");
String str = new String(data,0,len,"UTF-8");
System.out.println(str);
fis.close();
}}
/**
* 使用文件流完成复制文件操作
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 使用文件输入流读取原文件
* 使用文件输出流向复制文件写数据
*
* 利用块读写操作顺序从原文件将数据
* 读取出来写入复制文件完成复制操作。
*/
FileInputStream src
= new FileInputStream("music.mp3");
FileOutputStream desc
= new FileOutputStream("music_cp.mp3");
int len = -1;
byte[] data = new byte[1024*10];
while((len = src.read(data))!=-1) {
desc.write(data,0,len);
}
System.out.println("复制完毕!");
src.close();
desc.close();
}}
/**
* 缓冲流BufferedInputStream
* 缓冲流是一对高级流,功能是提高读写效率。
* 链接他们以后,无论我们进行随机读写还是
* 块读写,当经过缓冲流时都会被转换为块读写
* 操作。
* java.io.BufferedInputStream
* java.io.BufferedOutputStream
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileInputStream fis
= new FileInputStream("music.mp3");
BufferedInputStream bis
= new BufferedInputStream(fis);
FileOutputStream fos
= new FileOutputStream("music_cp.mp3");
BufferedOutputStream bos
= new BufferedOutputStream(fos);
int d = -1;
long start = System.currentTimeMillis();
while((d = bis.read())!=-1) {
bos.write(d);
}
long end = System.currentTimeMillis();
System.out.println("复制完毕,耗时:"+(end-start)+"ms");
bis.close();
bos.close();
}}
/**
* 缓冲输出流的缓冲区问题
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos
= new FileOutputStream("bos.txt");
BufferedOutputStream bos
= new BufferedOutputStream(fos);
String line = "你是隔壁的泰山,抓住爱情的藤蔓。";
byte[] data = line.getBytes("UTF-8");
/*
* 缓冲流的write方法并不是立即将数据写出,
* 而是先将数据存入其内部的数组中,当数组
* 装满时才会做一次真是写操作。(转化为块
* 写操作的过程)
*/
bos.write(data);
/*
* flush方法的意义是强制将缓冲流已经缓存的
* 数据一次性写出。这样做可以让写出的数据
* 有即时性,但是频繁调用会降低写效率。
* 在更关注写出的即时性时应当使用该方法。
*/
//bos.flush();
System.out.println("写出完毕!");
/*
* close方法中会调用一次flush方法
*/
bos.close();
}}
/**
* 对象流
* 对象流也是一对高级流,提供的功能是读写java
* 中的任何对象。
*
* 对象输出流:
* java.io.ObjectOutputStream
* 它可以将给定的java对象转换为一组字节然后
* 通过其连接的流将这些字节写出。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
Person p = new Person();
p.setName("苍老师");
p.setAge(18);
p.setGender("女");
String[] otherInfo = {"是一名演员","爱好是写毛笔字","已婚","促进中日文化交流","广大男性同胞的启蒙老师"};
p.setOtherInfo(otherInfo);
System.out.println(p);
FileOutputStream fos
= new FileOutputStream("person.obj");
ObjectOutputStream oos
= new ObjectOutputStream(fos);
/*
* 通过对象流写出对象的这个方法经历了
* 两个步骤:
* 1:对象流先将给定的对象转换为了一组
* 字节,这组字节包含对象本身保存的
* 数据信息,还包含该对象的结构信息
* 然后将这组字节通过其连接的流写出
*
* 上述操作对应的术语:对象序列化
*
*
* 2:经过文件流时,文件流将这组字节写
* 入到了文件中
*
* 将数据写入磁盘做长久保存的过程
* 对应的术语:数据持久化
*
*
*/
oos.writeObject(p);
System.out.println("写出完毕!");
oos.close();
}}
/**
* 对象输入流
* 可以进行对象的反序列化操作。
*
* 使用对象流读取的字节必须是通过对象输出流
* 序列化的一组字节才可以。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException, ClassNotFoundException {
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接口
* 与此同时,当前类中所有引用类型的属性,他们
* 对应的类也必须实现该接口。
* @author Mr.Cui
*/
public class Person implements Serializable{
/**
* 当一个类实现了Serializable接口后,要求
* 应当定义一个常量:serialVersionUID,即:
* 序列化版本号
*
* 序列化版本号影响反序列化是否成功。当对象
* 输入流在进行对象反序列化时会检查该对象与
* 当前类的版本是否一致,不一致则反序列化时
* 会抛出异常导致反序列化失败。
* 一致则可以进行反序列化,原则时对应的属性
* 进行还原。
*
* 如果我们不定义该版本号,编译器会在编译当前
* 类时根据结构生成一个版本号,但是一旦当前类
* 发生改变,那么版本号一定会改变。这样以前的
* 对象一定是不可以反序列化了。
*
*/
private static final long serialVersionUID = 1L;
private String name;
private int age;
private String gender;
/*
* transient关键字修饰的属性在对象序列化时
* 会被忽略。
* 忽略不必要的属性可以达到对象瘦身的作用。
*
*/
private transient String[] otherInfo;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public String[] getOtherInfo() {
return otherInfo;
}
public void setOtherInfo(String[] otherInfo) {
this.otherInfo = otherInfo;
}
public String toString() {
return name+","+age+","+gender+","+
Arrays.toString(otherInfo);
}}
/**
* 字符流
* java将流按照读写单位又进行了一种划分方式
* 字节流与字符流
* 字节流的读写单位是字节,而字符流的读写单位
* 是字符
* 所以字符流只适合读写文本数据!
*
* java.io.Reader,java.io.Writer
* 这两个类也是抽象类,是所有字符输入流与
* 字符输出流的父类,规定了读写字符的相关
* 方法。
*
* 转换流
* java.io.InputStreamReader
* java.io.OutputStreamWriter
* 他们是一对常用的字符流实现类,经常在我们做
* 字符数据读写操作中使用。并且在流链接中是
* 非常重要的一个环节。但是我们很少直接对它
* 做操作。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos
= new FileOutputStream("osw.txt");
OutputStreamWriter osw
= new OutputStreamWriter(fos,"UTF-8");
String line = "摩擦摩擦,在光滑的马路牙子上打出溜滑!";
osw.write(line);
line = "我的滑板鞋,时尚时尚最时尚!";
osw.write(line);
System.out.println("写出完毕!");
osw.close();
}}
/**
* 字符流
* java将流按照读写单位又进行了一种划分方式
* 字节流与字符流
* 字节流的读写单位是字节,而字符流的读写单位
* 是字符
* 所以字符流只适合读写文本数据!
*
* java.io.Reader,java.io.Writer
* 这两个类也是抽象类,是所有字符输入流与
* 字符输出流的父类,规定了读写字符的相关
* 方法。
*
* 转换流
* java.io.InputStreamReader
* java.io.OutputStreamWriter
* 他们是一对常用的字符流实现类,经常在我们做
* 字符数据读写操作中使用。并且在流链接中是
* 非常重要的一个环节。但是我们很少直接对它
* 做操作。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileOutputStream fos
= new FileOutputStream("osw.txt");
OutputStreamWriter osw
= new OutputStreamWriter(fos,"UTF-8");
String line = "摩擦摩擦,在光滑的马路牙子上打出溜滑!";
osw.write(line);
line = "我的滑板鞋,时尚时尚最时尚!";
osw.write(line);
System.out.println("写出完毕!");
osw.close();
}}
/**
* 转换流
* java.io.InputStreamReader
*
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileInputStream fis
= new FileInputStream("osw.txt");
InputStreamReader isr
= new InputStreamReader(fis,"UTF-8");
/*
* 字符流的方法:
* int read()
* 该方法是一次读取一个字符,实际读取
* 的字节量要根据指定的字符集决定。但
* 是当读取到该字符后在java中都是以一
* 个char形式保存(unicode)占2个字节。
*/
//int d = -1;
//while((d = isr.read())!=-1) {
//char c = (char)d;
//System.out.print(c);
//}
char[] data = new char[100];
int len = isr.read(data);
String str = new String(data,0,len);
System.out.println(str);
isr.close();
}}
/**
* java.io.PrintWriter
* 具有自动行刷新的缓冲字符输出流
* 开发中比较常用的字符高级流
*
* 可以按行写出字符串。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* PW提供了专门针对写文件的构造方法
* PrintWriter(String path)
* PrintWriter(File file)
*/
PrintWriter pw
= new PrintWriter("pw.txt","UTF-8");
pw.println("像一颗海草海草海草海草~");
pw.println("随波飘摇~");
System.out.println("写出完毕!");
pw.close();
}}
/**
* 在流链接中使用PW
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
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();
}}
/**
* 完成简易记事本工具
*
* 程序启动后,要求用户输入文件名,然后对该
* 文件进行写操作。
* 之后用户输入的每一行字符串都按行写入到该
* 文件中。
* 创建PW时要求使用流链接模式。
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
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时
* 允许指定第二个参数,该参数为一个
* boolean值,当这个值为true时,当前
* PW具有自动行刷新功能。
* 即:每当调用println方法写出一行字符串
* 时就会自动flush.
* 注意:print方法是不会自动flush的
*/
PrintWriter pw
= new PrintWriter(bw,true);
System.out.println("请开始输入内容:");
//用来记录每次用户输入的字符串
String line = null;
while(true) {
line = scanner.nextLine();
if("exit".equals(line)) {
break;
}
pw.println(line);
//pw.flush();
}
System.out.println("再见!");
pw.close();
}}
/**
* 缓冲字符输入流:
* java.io.BufferedReader
* 特点:可以按行读取字符串
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
/*
* 将当前源代码输出到控制台
*/
FileInputStream fis
= new FileInputStream(
"src/io/BrDemo.java"
);
InputStreamReader isr
= new InputStreamReader(fis);
BufferedReader br
= new BufferedReader(isr);
/*
* String readLine()
* 读取一行字符串
* 顺序读取若干字符,当读取到了换行
* 符时停止,并将换行符之前的字符组
* 成一个字符串返回。返回的字符串中
* 是不含有最有的换行符的。
* 若返回值为null,说明流读取到了
* 末尾。
*/
String line = null;
while((line = br.readLine())!=null) {
System.out.println(line);
}
br.close();
}}
/**
* 使用文件输入流读取文件数据
* @author Mr.Cui
*/
public static void main(String[] args) throws IOException {
FileInputStream fis
= new FileInputStream("fos.txt");
byte[] data = new byte[200];
int len = fis.read(data);
System.out.println("实际读取了:"+len+"个字节");
String str = new String(data,0,len,"UTF-8");
System.out.println(str);
fis.close();
}}
/**
* java异常处理机制中的try-catch
* try语句块用来包含可能出错的代码片段,catch
* 用来捕获这些错误并针对该错误进行处理。
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = "a";
System.out.println(str.length());
System.out.println(str.charAt(0));
System.out.println(Integer.parseInt(str));
//try语句块中出错代码以下内容不执行
System.out.println("!!!!!");
}catch(NullPointerException e) {
System.out.println("出现了空指针");
}catch(StringIndexOutOfBoundsException e) {
System.out.println("字符串下标越界了!");
/*
* 应当在最后一个catch处捕获Exception
* 尽量避免一个未捕获异常导致程序中断
*/
}catch(Exception e) {
System.out.println("反正就是出了个错!");
}
System.out.println("程序结束了");
}}
/**
* finally块
* finally是异常处理机制的最后一块,可以直接
* 跟在try之后或者最后一个catch之后。
* finally可以确保只要程序运行到try语句块中
* 那么无论是否抛出异常,finally中的代码必定
* 执行。
*
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = null;
System.out.println(str.length());
return;
} catch (Exception e) {
System.out.println("出错了");
} finally {
System.out.println("finally!!!");
}
System.out.println("程序结束了");
}}
/**
* 在IO操作中使用异常处理机制
* @author Mr.Cui
*/
public static void main(String[] args) {
FileOutputStream fos = null;
try {
fos = new FileOutputStream("fos.dat");
fos.write(1);
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(fos!=null) {
fos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}}}
/**
* JDK7之后推出了一个新特性:autoclose
* 允许编译器在编译过程中自动处理诸如流的关闭
* 工作。
* @author Mr.Cui
*/
public static void main(String[] args) {
try(
/*
* 实现了AutoCloseable接口的类可以在
* 这里定义。编译器最终会将代码改变,
* 在finally中将其关闭
*/
FileOutputStream fos
= new FileOutputStream("fos.dat");
){
fos.write(1);
} catch (IOException e) {
e.printStackTrace();
}
}}
/**
* 请分别说明:
* final finally finalize?
*
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println(
test("0")+","+test(null)+","+test("")
); //3,3,3
}
public static int test(String str) {
try {
System.out.println("str:"+str);
return str.charAt(0)-'0';
} catch( NullPointerException e) {
System.out.println("空指针!");
return 1;
} catch (Exception e) {
System.out.println("其他异常!");
return 2;
} finally {
return 3;
}}}
/**
* 测试异常的抛出
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
Person p = new Person();
/*
* 满足语法,但是不满足业务逻辑要求
* 这时setAge方法中可以当做异常抛出
* 要求这里调用时处理
*/
try {
/*
* 当调用一个含有throws声明异常抛出
* 的方法时,要求必须处理该异常
* 而处理方式有两种:
* 1:使用try-catch捕获并解决异常
* 2:在当前方法上继续使用throws声明
* 该异常的抛出
*/
p.setAge(10);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(p.getAge());
System.out.println("程序结束了");
}}
/**
* 使用当前类测试异常的抛出
* @author Mr.Cui
*/
private int age;
public int getAge() {
return age;
}
/**
* 通常一个方法中使用throw抛出一个异常时
* 就要在方法声明时使用throws声明该异常的
* 抛出以通知调用者解决该异常。
* 只有抛出RuntimeException及其子类型异常
* 时可以不要求这样做。
* @param age
* @throws Exception
*/
public void setAge(int age)throws Exception {
if(age<0||age>100) {
throw new Exception("年龄不合法!");
}
this.age = age;
}}
/**
* 重写超类含有throws声明异常抛出的方法时
* 对throws的重写规则
* @author ta
*
*/
public void dosome()
throws IOException,AWTException {
}}
class Son extends ThrowsDemo{
//public void dosome()
//throws IOException,AWTException {
//}
//允许仅抛出部分异常
//public void dosome()
//throws IOException{
//}
//允许不再抛出任何异常
//public void dosome(){
//}
//允许抛出超类方法抛出异常的子类型异常
//public void dosome()
//throws FileNotFoundException {
//}
//不允许抛出额外异常
//public void dosome()
//throws SQLException {
//}
//不允许抛出超类方法抛出异常的父类型异常
//public void dosome()
//throws Exception{
//}}
package exception;
/**
* 异常常用方法
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
try {
String str = "A";
System.out.println(Integer.parseInt(str));
} catch (Exception e) {
//输出错误信息,最常用
//e.printStackTrace();
//获取错误消息
String message = e.getMessage();
System.out.println(message);
}
System.out.println("程序结束了");
}}
/**
* 年龄不合法异常
*
* 自定义异常,通常是用来说明当前项目的某个
* 业务逻辑错误。
* @author Mr.Cui
*/
private static final long serialVersionUID = 1L;
public IllegalAgeException() {
super();
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message, Throwable cause) {
super(message, cause);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(String message) {
super(message);
// TODO Auto-generated constructor stub
}
public IllegalAgeException(Throwable cause) {
super(cause);
// TODO Auto-generated constructor stub
} }
/**
* 使用当前类测试异常的抛出
* @author Mr.Cui
*/
private int age;
public int getAge() {
return age;
}
/**
* 通常一个方法中使用throw抛出一个异常时
* 就要在方法声明时使用throws声明该异常的
* 抛出以通知调用者解决该异常。
* 只有抛出RuntimeException及其子类型异常
* 时可以不要求这样做。
* @param age
* @throws Exception
*/
public void setAge(int age)throws IllegalAgeException {
if(age<0||age>100) {
throw new IllegalAgeException("年龄不合法!");
}
this.age = age;
} }
/**
* 测试异常的抛出
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
Person p = new Person();
/*
* 满足语法,但是不满足业务逻辑要求
* 这时setAge方法中可以当做异常抛出
* 要求这里调用时处理
*/
try {
/*
* 当调用一个含有throws声明异常抛出
* 的方法时,要求必须处理该异常
* 而处理方式有两种:
* 1:使用try-catch捕获并解决异常
* 2:在当前方法上继续使用throws声明
* 该异常的抛出
*/
p.setAge(10);
} catch (IllegalAgeException e) {
e.printStackTrace();
}
System.out.println(p.getAge());
System.out.println("程序结束了");
}}
/**
* 线程是并发运行代码的。
* 有两种创建线程的方式:
* 方式一,继承Thread并重写run方法。run方法中
* 就是希望线程执行的逻辑。
* @author ta
*
*/
public class ThreadDemo1 {
public static void main(String[] args) {
Thread t1 = new MyThread1();
Thread t2 = new MyThread2();
/*
* 启动线程要调用start方法,而不是
* 直接调用run方法。当start方法调用
* 完毕后,run方法很快会被线程自行调
* 用。
*/
t1.start();
t2.start();
}
}
/**
* 第一种创建线程的方式比较简单直接,但是缺点
* 主要有两个:
* 1:由于需要继承线程,这导致不能再继承其他类
* 实际开发中经常要复用某个超类的功能,那么
* 在继承线程后不能再继承其他类会有很多不便
*
* 2:定义线程类的同时重写了run方法,这会导致
* 线程与线程要执行的任务有一个必然的耦合
* 关系,不利于线程的重用。
* @author Mr.Cui
*/
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("你是谁啊?");
}
}}
class MyThread2 extends Thread{
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("我是查水表的!");
}
}}
/**
* 第二种创建线程的方式
* 实现Runnable接口,单独定义线程任务
* @author Mr.Cui
*/
public static void main(String[] args) {
//实例化两个任务
Runnable r1 = new MyRunnable1();
Runnable r2 = new MyRunnable2();
//创建两个线程并指派任务
Thread t1 = new Thread(r1);
Thread t2 = new Thread(r2);
t1.start();
t2.start();
}}
class MyRunnable1 implements Runnable{
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("你是谁啊?");
}
}}
class MyRunnable2 implements Runnable{
public void run() {
for(int i=0;i<1000;i++) {
System.out.println("我是查水表的!");
}
}}
/**
* 线程提供了获取相关信息的方法
* @author Mr.Cui
*/
public static void main(String[] args) {
/*
* 线程提供了一个静态方法:
* static Thread currentThread()
* 该方法用来获取运行这个方法的线程
* main方法也是靠一个线程运行的,当JVM启动
* 后会自动创建一个线程来执行main方法。而
* 这个线程的名字叫做"main",我们称它为主线程
*
* 获取运行main方法的线程
*
*/
Thread main = Thread.currentThread();
System.out.println("运行main方法的线程:"+main);
dosome();
Thread t = new Thread() {
public void run() {
Thread t = Thread.currentThread();
System.out.println("自定义线程:"+t);
dosome();
}
};
t.start();
}
public static void dosome() {
Thread t = Thread.currentThread();
System.out.println("运行dosome方法的线程是:"+t);
}}
/**
* 线程提供了获去自身信息的相关方法
* @author Mr.Cui
*/
public static void main(String[] args) {
Thread main = Thread.currentThread();
//获去线程的名字
String name = main.getName();
System.out.println("name:"+name);
//获去线程的唯一标识(id)
long id = main.getId();
System.out.println("id:"+id);
//获去线程的优先级
int priority = main.getPriority();
System.out.println("优先级:"+priority);
//线程是否还处于活动状态
boolean isAlive = main.isAlive();
System.out.println("isAlive:"+isAlive);
//线程是否是被中断了
boolean isInterrupted = main.isInterrupted();
System.out.println("isInterrupted:"+isInterrupted);
//线程是否为守护线程
boolean isDaemon = main.isDaemon();
System.out.println("isDaemon:"+isDaemon);
}}
/**
* 线程的优先级
* 线程不能主动获去CPU时间片,只能被动的被
* 线程调度器分配。
* 调整线程的优先级可以最大程度的改善某个线程
* 获去CPU时间片的次数。
* 理论上线程优先级约高的线程获去CPU时间片的
* 次数就越多。
* @author Mr.Cui
*/
public static void main(String[] args) {
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();
}}
/**
* 线程提供了一个静态方法:
* static void sleep(long ms)
* 使运行这个方法的线程阻塞指定毫秒。超时后
* 该线程会自动回到RUNNABLE状态,等待再次并发
* 运行。
* @author Mr.Cui
*/
public static void main(String[] args) {
System.out.println("程序开始了");
while(true) {
System.out.println("你好!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}}}
/**
* 倒计时程序
* 程序启动后,要求输入一个数字,比如:100
* 然后每秒输出一次,每次输出数字递减。
* 输出到0时提示结束,程序退出。
* @author Mr.Cui
*/
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字:");
String line = scanner.nextLine();
Integer num = Integer.parseInt(line);
for(;num>0;num--) {
System.out.println(num);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("结束!");
}}
/**
* sleep方法要求必须处理中断异常,原因在于当
* 一个线程调用了sleep方法处于阻塞状态的过程
* 中若被调用了它的interrupt()方法中断时,它
* 就会在sleep方法中抛出中断异常。这时并非是
* 将这个线程直接中断,而是中断了它的阻塞状态
* @author Mr.Cui
*
*/
public static void main(String[] args) {
/*
* JDK8之前,由于JVM内存分配问题,有一个
* 要求:
* 当一个方法的局部变量被这个方法的其他
* 局部内部类所引用是,这个变量声明必须
* 是final的。
*/
final Thread lin = new Thread() {
public void run() {
System.out.println("林:刚美完容,睡一会吧!");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
System.out.println("林:干嘛呢!干嘛呢!干嘛呢!都破了相了!");
}
System.out.println("林:醒了!");
}
};
Thread huang = new Thread() {
public void run() {
System.out.println("黄:开始砸墙!");
for(int i=0;i<5;i++) {
System.out.println("黄:80!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("咣当!");
System.out.println("黄:搞定!");
//中断lin线程
lin.interrupt();
}
};
lin.start();
huang.start();
}}
/**
* 守护线程
* 守护线程又称为后台线程,默认创建的线程都
* 是普通线程或称为前台线程,线程提供了一个
* 方法:
* void setDaemon(boolean on)
* 只有调用该方法并传入参数true时,该线程才
* 会被设置为守护线程。
*
*
* 守护线程在使用上与普通线程没有差别,但是在
* 结束时机上有一个区别,即:线程结束时所有正在
* 运行的守护线程都会被强制停止。
*
* 线程的结束:当一个进程中所有的普通线程都结束
* 时,进程即结束。
*
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Thread rose = new Thread() {
public void run() {
for(int i=0;i<5;i++) {
System.out.println("rose:let me go!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
System.out.println("rose:啊啊啊啊啊AAAAAAAaaaaaa.....");
System.out.println("噗通!");
}
};
Thread jack = new Thread() {
public void run() {
while(true) {
System.out.println("jack:you jump!i jump!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
}
};
rose.start();
/*
* 设置为守护线程
* 注意,必须在线程启动前进行设置
*/
jack.setDaemon(true);
jack.start();
}}
/**
* 线程提供了一个方法:
* void join()
* 该方法可以协调线程之间的同步运行
*
* 同步与异步:
* 同步运行:运行有顺序
* 异步运行:运行代码无顺序,多线程并发运行就
* 是异步运行
* @author Mr.Cui
*
*/
//标识图片是否下载完毕
private static boolean isFinish = false;
public static void main(String[] args) {
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(20);
} catch (InterruptedException e) {
}
}
System.out.println("down:下载图片完毕!");
isFinish = true;
}
};
Thread show = new Thread() {
public void run() {
System.out.println("show:开始显示图片");
//加载图片前应先等待下载线程将图片下载完毕
try {
/*
* show线程在调用download.join()方法后
* 就进入了阻塞状态,直到download线程
* 的run方法执行完毕才会解除阻塞
*/
download.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
if(!isFinish) {
throw new RuntimeException("加载图片失败!");
}
System.out.println("show:显示图片完毕!");
}
};
download.start();
show.start();
}}
/**
* 同步块
* 语法:
* synchronized(同步监视器对象){
* 需要同步运行的代码片段
* }
*
* 同步块可以更精确的控制需要同步运行的代码
* 片段。有效的缩小同步范围可以在保证并发安全
* 的前提下提高代码并发运行的效率
* 使用同步块控制多线程同步运行必须要求这些
* 线程看到的同步监视器对象为[同一个]。
*
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Shop shop = new Shop();
Thread t1 = new Thread() {
public void run() {
shop.buy();
}
};
Thread t2 = new Thread() {
public void run() {
shop.buy();
}
};
t1.start();
t2.start();
}
}
class Shop{
// public synchronized void buy() {
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) {
}
}}
/**
* 多线程并发的安全问题。
* 产生:当多个线程并发操作同一资源时,由于线程
* 切换实际的不确定性,会导致执行操作资源的代码
* 顺序未按照设计顺序执行,出现操作混乱的情况。
* 严重时可能导致系统瘫痪。
*
* 解决:将并发操作同一资源改为同步操作,即:有
* 先后顺序的操作。
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Table table = new Table();
Thread t1 = new Thread() {
public void run() {
while(true) {
int bean = table.getBean();
Thread.yield();
System.out.println(getName()+":"+bean);
}
}
};
Thread t2 = new Thread() {
public void run() {
while(true) {
int bean = table.getBean();
Thread.yield();
System.out.println(getName()+":"+bean);
}
}
};
t1.start();
t2.start();
}
}
class Table{
//20个豆子
private int beans = 20;
/**
* 当一个方法被synchronized修饰后,该方法
* 称为"同步方法",即:多个线程不能同时在方
* 法内部运行。强制让多个线程在执行同一个
* 方法时变为同步操作就解决了并发安全问题
*
* 在方法上使用synchronized,那么同步监视器
* 对象就是当前方法所属对象,即:方法内部看到
* 的this
* @return
*/
public synchronized int getBean() {
if(beans==0) {
throw new RuntimeException("没有豆子了!");
}
//模拟线程执行到这里没有时间了
Thread.yield();
return beans--;
}
}
/**
* 静态方法若使用synchroinzed修饰,那么该方法
* 一定具有同步效果
* 静态方法对应的同步监视器对象为当前类的
* 类对象(Class的实例)。类对象会在后面反射
* 的课程中讲到。
* @author Mr.Cui
*/
public static void main(String[] args) {
Thread t1 = new Thread() {
public void run() {
Foo.dosome();
}
};
Thread t2 = new Thread() {
public void run() {
Foo.dosome();
}
};
t1.start();
t2.start();
}
}
class Foo{
public synchronized static void dosome() {
Thread t = Thread.currentThread();
System.out.println(t.getName()+":正在运行dosome方法");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(t.getName()+":运行dosome方法完毕");
}}
/**
* 互斥锁
* 当多个代码片段被synchronized块修饰后,这些
* 同步块的同步监听器对象又是同一个时,这些
* 代码片段就是互斥的。多个线程不能同时在这些
* 方法中运行。
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Boo boo = new Boo();
Thread t1 = new Thread() {
public void run() {
boo.methodA();
}
};
Thread t2 = new Thread() {
public void run() {
boo.methodB();
}
};
t1.start();
t2.start();
}
}
class Boo{
public synchronized void methodA() {
Thread t = Thread.currentThread();
try {
System.out.println(t.getName()+":正在运行A方法");
Thread.sleep(5000);
System.out.println(t.getName()+":运行A方法完毕");
} catch (Exception e) {
}
}
public void methodB() {
synchronized (this) {
Thread t = Thread.currentThread();
try {
System.out.println(t.getName()+":正在运行B方法");
Thread.sleep(5000);
System.out.println(t.getName()+":运行B方法完毕");
} catch (Exception e) {
}
}} }
/**
* java.util.Collection
* 集合
* 集合与数组相似,可以保存一组元素,并且提供
* 了操作集合元素的相关方法,使用便捷。
* Collection接口下面有两个常见的子接口:
* java.util.List:可重复集合,并且有序,可以
* 通过下标操作元素。
*
* java.util.Set:不可重复集合。
* 元素是否重复是依靠元素自身equals比较进行
* 判定的.
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Collection c = new ArrayList();
/*
* boolean add(E e)
* 向当前集合中添加给定元素,当该元素
* 成功添加则返回true。
*/
c.add("one");
c.add("two");
c.add("three");
c.add("four");
c.add("five");
System.out.println(c);
/*
* int size()
* 返回当前集合的元素个数
*/
int size = c.size();
System.out.println("size:"+size);
/*
* boolean isEmpty()
* 判断当前集合是否为空集(不含有任何
* 元素)
*/
boolean isEmpty = c.isEmpty();
System.out.println("isEmpty:"+isEmpty);
/*
* void clear()
* 清空当前集合
*/
c.clear();
System.out.println("集合已清空");
System.out.println(c);
System.out.println("size:"+c.size());
System.out.println("isEmpty:"+c.isEmpty());
}}
/**
* 集合提供了判断是否包含给定元素的方法:
* boolean contains(E e)
*
* @author Mr.Cui
*
*/
public class ContainsDemo {
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));
/*
* 集合的toString方法会将每个元素
* 的toString体现出来。
*/
System.out.println(c);
Point p = new Point(1,2);
// c.add(p);
/*
* contains方法是依靠元素自身equals比较
* 的结果判别集合是否包含该元素
*/
boolean contains = c.contains(p);
System.out.println("包含:"+contains);
}}
/**
* 集合只能存放引用类型元素,并且存放的也是元
* 素的引用(地址)
* @author Mr.Cui
*
*/
public static void main(String[] args) {
Collection c = new ArrayList();
Point p = new Point(1,2);
c.add(p);
System.out.println("c:"+c);
System.out.println("p:"+p);
p.setX(2);
System.out.println("c:"+c);//[(2,2)]
System.out.println("p:"+p);//(2,2)
}}
___________________________________________________________________{
public class Test {
public static void main(String[] args) {
int a = 1;
String b = "hello";
Point p = new Point(1,2);
Collection c = new ArrayList();
c.add(p);
test(a, b, p, c);
System.out.println("a:"+a);//?
System.out.println("b:"+b);//?
System.out.println("p:"+p);//?
System.out.println("c:"+c);//?
}
public static void test(int a,String b,Point p,Collection c){
a = 2;
b = b+"world";
p.setX(3);
p = new Point(5,6);
c.clear();
c.add(p);
p.setY(7);
c = new ArrayList();
c.add(p);
}
}
/**
* 使用当前类实例作为集合元素,测试集合相关
* 操作。
* @author Mr.Cui
*
*/
public class Point {
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String toString() {
return "("+x+","+y+")";
}
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj == this) {
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x==p.x&&this.y==p.y;
}
return false;
}}
/**
* 删除集合元素
* @author Mr.Cui
*/
public class RemoveDemo {
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));
c.add(new Point(1,2));
System.out.println(c);
Point p = new Point(1,2);
/*
* 删除元素也是依靠元素equals比较判定
*/
c.remove(p);
System.out.println(c);
}}
/**
* 集合操作
* @author Mr.Cui
*
*/
public class CollectionDemo3 {
public static void main(String[] args) {
Collection c1 = new ArrayList();
c1.add("java");
c1.add("c");
c1.add("c++");
System.out.println("c1:"+c1);
Collection c2 = new HashSet();
c2.add("php");
c2.add(".net");
c2.add("java");
System.out.println("c2:"+c2);
/*
* boolean addAll(Collection c)
* 将给定集合中的所有元素添加到
* 当前集合中。
*/
c2.addAll(c1);
System.out.println("c2:"+c2);
Collection c3 = new ArrayList();
c3.add("c");
c3.add(".net");
c3.add("android");
System.out.println("c3:"+c3);
/*
* boolean containsAll(Collection c)
* 判断当前集合是否包含给定集合中的
* 所有元素
*/
boolean ca = c2.containsAll(c3);
System.out.println("全包含:"+ca);
/*
* 删除当前集合与给定集合的共有元素
*/
c2.removeAll(c3);
System.out.println(c2);
}}
/**
* 集合提供了同一的遍历元素方式:迭代器模式
*
* 对应方法:
* Iterator iterator()
* 该方法可以获取一个用来遍历当前集合的迭代器
* 实现类,通过它遍历元素
*
* java.util.Iterator接口
* 迭代器接口,规定了迭代器遍历集合的相关操作
* 不同的集合都实现了一个用于遍历自身元素的
* 迭代器实现类。
*
* 迭代器遍历集合元素遵循的过程:问,取,删
* 其中删除元素不是必要操作
*
* @author Mr.Cui
*
*/
public class IteratorDemo {
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();
/*
* boolean hasNext()
* 判断集合是否还有元素可以迭代
*/
while(it.hasNext()) {//问
/*
* E next()
* 迭代集合下一个元素
*/
String o = (String)it.next();//取
if("#".equals(o)) {
// c.remove(o);
/*
* 删除的是通过next方法取出
* 的元素
*/
it.remove();//删
}
System.out.println(o);
}
System.out.println(c);
}}
——————————————————————————————}
/**
* JDK5推出时,推出了一个新的特性:
* 增强型for循环,也称为新循环,for each
*
* 新循环不取代传统for循环的工作,它专门设计
* 是用来遍历集合或数组的。
*
* @author Mr.Cui
*/
public static void main(String[] args) {
String[] array = {"one","two","three","four"};
for(int i=0;i<array.length;i++) {
System.out.println(array[i]);
}
/*
* 新循环的语法也是编译器认可,而非虚拟机
* 认可。编译器会在编译源代码时将新循环
* 遍历数组改为传统for循环遍历的方式
*/
for(String str : array) {
System.out.println(str);
}
}}
/**
* 使用新循环遍历集合
* @author Mr.Cui
*/
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("one");
c.add("two");
c.add("three");
c.add("four");
c.add("five");
System.out.println(c);
/*
* 新循环遍历集合会被编译器改为使用
* 迭代器遍历。所以在遍历的过程中是
* 不能通过集合的方法增删元素的。
*/
for(Object o : c) {
String str = (String)o;
System.out.println(str);
}
}}
/**
* 泛型
* 泛型是JDK5推出的特性, 也称为参数化类型
* 它允许将一个类中属性的类型,方法参数的类型
* 以及方法返回值类型等的定义权移交给使用者。
* 这使得实际应用中使用这个类更加灵活便捷。
* @author Mr.Cui
*/
public class Location<E> {
private E x;
private E y;
public Location(E x, E y) {
super();
this.x = x;
this.y = y;
}
public E getX() {
return x;
}
public void setX(E x) {
this.x = x;
}
public E getY() {
return y;
}
public void setY(E y) {
this.y = y;
}
@Override
public String toString() {
return "("+x+","+y+")";
}}
/**
* 测试泛型
* @author Mr.Cui
*/
public class TypeDemo {
public static void main(String[] args) {
Location<Integer> loc1 = new Location<Integer>(1,2);
loc1.setX(2);
int x1 = loc1.getX();
System.out.println("loc1:"+loc1);
System.out.println("x1:"+x1);
Location<Double> loc2 = new Location<Double>(1.1,2.2);
loc2.setX(2.2);
double x2 = loc2.getX();
System.out.println("loc2:"+loc2);
System.out.println("x2:"+x2);
Location<String> loc3 = new Location<String>("一","二 ");
loc3.setX("三");
String x3 = loc3.getX();
}}
**
* 泛型是编译器认可,而非虚拟机。
* 编译器会将泛型改为Object。所以泛型的实际
* 类型就是Object
* 在使用泛型时,编译器会辅助做两个操作
* 1:对泛型设置值时,编译器会检查该值的类型
* 是否与泛型一致,不一致则编译不通过。
* 2:在获取泛型值时,编译器会添加向下造型的
* 代码。
* @author Mr.Cui
*/
public static void main(String[] args) {
Location<Integer> loc1 = new Location<Integer>(1,2);
/*
* 编译器会检查实际赋值是否符合泛型类型
* 要求,不符合编译不通过。
*/
loc1.setX(1);
// loc1.setX("1");//编译不通过
/*
* 编译器会在编译时补全向下造型的代码为:
* int x1 = (Integer)loc1.getX();
* 然后还会触发自动拆箱,改为
* int x1 = ((Integer)loc1.getX()).intValue();
*/
int x1 = loc1.getX();
System.out.println("loc1:"+loc1);
System.out.println("x1:"+x1);
/*
* 泛型可以不指定,不指定则按照默认的
* Object看待
*/
Location loc2 = loc1;
System.out.println("loc2:"+loc2);
loc2.setX("三");
System.out.println("loc2:"+loc2);
//再次以loc1角度获取x
//x1 = (Integer)loc1.getX();
x1 = loc1.getX();//类造型异常
System.out.println("x1:"+x1);
}}
/**
* 泛型在集合当中的应用---约束集合中的元素类型
* @author M.Cui
*/
public static void main(String[] args) {
Collection<String> c = new ArrayList<String>();
/*
* 指定后add方法只能传入泛型要求的
* 元素
*/
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);
}
}}
/**
* java.util.List接口
* List继承自Collection
* List的特点:可重复,并且有序,提供了一组可以
* 通过下标操作元素的方法。
*
* 常用实现类:
* java.util.ArrayList:内部由数组实现,查询
* 性能更好。
* java.util.LinkedList:内部由链表实现,增删
* 元素性能更好,尤其首尾增删元素。
* 在对性能没有特别苛刻要求下,通常使用的是
* ArrayList即可。
*
* @author Mr.Cui
*/
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.add("five");
System.out.println(list);
/*
* E get(int index)
* 获取给定下标对应的元素
*/
String str = list.get(1);
System.out.println(str);
//List可以用普通的for循环遍历
for(int i=0;i<list.size();i++) {
str = list.get(i);
System.out.println(str);
}
/*
* E set(int index, E e)
* 将给定元素设置到指定位置,返回值为
* 原位置对应元素。所以set方法的意义是
* 替换元素操作
*/
//[one,2,three,four,five]
String old = list.set(1, "2");
System.out.println(list);
System.out.println(old);
}}
/**
* List提供了一对重载的add,remove方法
* @author Mr.Cui
*/
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.add("five");
System.out.println(list);
/*
* void add(int index,E e)
* 将给定元素插入到指定位置
*
* [one,2,two,three,four,five]
*/
list.add(1, "2");
System.out.println(list);
/*
* E remove(int index)
* 删除并返回给定位置对应的元素
* [one,2,three,four,five]
*/
String old = list.remove(2);
System.out.println(list);
System.out.println(old);
}}
/**
* 使用当前类实例作为集合元素,测试集合相关
* 操作。
* @author Mr.Cui
*/
public class Point
implements Comparable<Point>{
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String toString() {
return "("+x+","+y+")";
}
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj == this) {
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x==p.x&&this.y==p.y;
}
return false;
}
/**
* 当一个类实现了Comparable接口后必须重写
* 方法:compareTo
* 该方法的作用是比较当前对象this与方法的
* 参数对象o之间的大小。
*
* 返回值不关心具体取值,只关心取值范围
* 当返回值>0:当前对象大于参数对象(this>o)
* 当返回值<0:当前对象小于参数对象
* 当返回值=0:两个对象相等
*/
public int compareTo(Point o) {
int len = this.x*this.x+this.y*this.y;
int olen = o.x*o.x+o.y*o.y;
return len-olen;
}
}
/**
* 获取子集操作
* List subLis(int start,int end)
* 获取当前集合指定下标对应范围内的元素
* @author Mr.Cui
*/
public static void main(String[] args) {
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);
/*
* 将子集每个元素扩大10倍
*/
for(int i=0;i<subList.size();i++) {
subList.set(i,subList.get(i)*10);
}
System.out.println(subList);
/*
* 操作子集就是对原集合对应元素的操作
*/
System.out.println(list);
/*
* 将list集合中2-8删除
*/
list.subList(2, 9).clear();
System.out.println(list);
}}
/**
* 集合转换为数组
* 集合提供了一个方法:toArray,可以将当前
* 集合转换为一个数组
* @author Mr.Cui
*/
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);
// Object[] array = c.toArray();
String[] array
= c.toArray(new String[c.size()]);
System.out.println(array.length);
System.out.println(Arrays.toString(array));
}}
/**
* 数组转换为List集合。
* 通过数组的工具类:Arrays的静态方法asList
* 可以将一个数组转换为一个List
*
* @author Mr.Cui
*/
public static void main(String[] args) {
String[] array = {"one","two","three","four"};
List<String> list
= Arrays.asList(array);
System.out.println(list);
/*
* 数组转换的集合对其元素操作就是对
* 原数组对应元素的操作
*/
list.set(1, "2");
System.out.println(list);
System.out.println("array:"+Arrays.toString(array));
/*
* 由于数组是定长的,所以不支持集合
* 的增删操作,下面的操作会抛出异常
*/
// list.add("five");
/*
* 所有的集合都提供了一个参数为Collection
* 的构造方法,作用是在创建当前集合的同时
* 包含给定集合中的所有元素
*/
List<String> list2
= new ArrayList<String>(list);
list2.add("five");
System.out.println(list2);
}}
/**
* 集合工具类:java.util.Collections
* 其提供了一个静态方法:sort,可以对List集合
* 进行自然排序(从小到大)
* @author Mr.Cui
*/
public static void main(String[] args) {
List<Integer> list
= new ArrayList<Integer>();
Random random = new Random();
for(int i=0;i<10;i++) {
list.add(random.nextInt(100));
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
}}
/**
* 排序自定义类型元素
* @author Mr.Cui
*/
public class SortListDemo2 {
public static void main(String[] args) {
List<Point> list = new ArrayList<Point>();
list.add(new Point(3,4));
list.add(new Point(4,9));
list.add(new Point(2,7));
list.add(new Point(8,1));
list.add(new Point(6,0));
list.add(new Point(4,4));
System.out.println(list);
/*
* Collections的sort方法排序的集合要求
* 元素必须实现Comparable接口。
*/
Collections.sort(list);
System.out.println(list);
}}
/**
* 创建一个List集合,并存放10个随机数,然后排序该集合
* 后输出
* @author Mr.Cui
*/
public static void main(String[] args){
List<Integer> l = new ArrayList<Integer>();
Random random = new Random();
for(int a =0; a<10;a++){
l.add(random.nextInt(100));
}
System.out.println("10个"+"随机数:"+l);
Collections.sort(l);
System.out.println("排序后为:"+
l);
}}
/**
* 使用当前类实例作为集合元素,测试集合相关
* 操作。
*
* 侵入性
* @author Mr.Cuis
*/
public class Point
implements Comparable<Point>{
private int x;
private int y;
public Point(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public String toString() {
return "("+x+","+y+")";
}
public boolean equals(Object obj) {
if(obj == null) {
return false;
}
if(obj == this) {
return true;
}
if(obj instanceof Point) {
Point p = (Point)obj;
return this.x==p.x&&this.y==p.y;
}
return false;
}
/**
* 当一个类实现了Comparable接口后必须重写
* 方法:compareTo
* 该方法的作用是比较当前对象this与方法的
* 参数对象o之间的大小。
*
* 返回值不关心具体取值,只关心取值范围
* 当返回值>0:当前对象大于参数对象(this>o)
* 当返回值<0:当前对象小于参数对象
* 当返回值=0:两个对象相等
*/
public int compareTo(Point o) {
int len = this.x*this.x+this.y*this.y;
int olen = o.x*o.x+o.y*o.y;
return len-olen;
}}
/**
* 排序自定义类型元素
* @author Mr.Cui
*/
public static void main(String[] args) {
List<Point> list = new ArrayList<Point>();
list.add(new Point(3,4));
list.add(new Point(4,9));
list.add(new Point(2,7));
list.add(new Point(8,1));
list.add(new Point(6,0));
list.add(new Point(4,4));
System.out.println(list);
/*
* Collections的sort方法排序的集合要求
* 元素必须实现Comparable接口。
*
* 如果是排序自定义类型元素,强烈建议
* 不使用这种方式,因为这个sort方法对
* 我们的代码有侵入性(它要求Point必须
* 为它实现接口,并重写方法)
* 由于java API中很多类已经实现了该接口,
* 比如包装类,String等,那么在排序这
* 样元素的集合时可以直接用下面这个sort
*/
//排序.sort Collections.sort(list);
System.out.println(list);
}}
/**
* 排序字符串
* @author Mr.Cui
*/
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("小泽老师");
list.add("传奇");
list.add("苍老师");
System.out.println(list);
/*
* String已经实现了Comparable接口
* 比较规则为按照每个字符的unicode编码
* 比较。
* 对于排序中文时,没有什么意义。
*
* 对此,该sort方法的使用相对局限。
* 所以当:
* 排序自定义类型元素或java提供的已经实现
* 过Comparable接口的元素,但是比较方法不
* 满足我们排序需求时,都不应当使用下面的
* sort方法
*
*/
Collections.sort(list);
System.out.println(list);
}}
/**
* Collections提供了一个重载的sort方法,该
* 方法除了要求传入要排序的集合外,还要求再
* 传入一个比较器(Comparator),该比较器可以
* 定义一种比较规则,该sort方法会用这个比较
* 规则对集合元素比较后进行排序。
*
* @author Mr.Cui
*/
public class SortListDemo4 {
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
list.add("传奇");
list.add("小泽老师");
list.add("苍老师");
System.out.println(list);
/*
* 这种排序方法不要求集合元素必须实现Comparable
* 接口,对此在排序自定义元素时不对我们的代码
* 产生额外侵入,由于可以自定比较规则,对于像
* String这样已经实现类比较方法的可以做到按照
* 我们的比较规则排序。
* 开发中推荐中这种方式排序.
*/
Collections.sort(
list,new Comparator<String>() {
public int compare(String o1, String o2){
//按照字符多少比大小
return o1.length()-o2.length();
}
});
System.out.println(list);
}}
/**
* java.util.Queue
* Queue接口继承自Collection。
* 队列也可以保存一组元素,但是存取元素必须
* 遵循先进先出模式。
* 常用实现类:LinkedList
* @author Mr.Cui
*/
public class QueueDemo {
public static void main(String[] args) {
Queue<String> queue
= new LinkedList<String>();
/*
* offer是入队操作,向队列末尾追加
* 元素
*/
queue.offer("one");
queue.offer("two");
queue.offer("three");
queue.offer("four");
queue.offer("five");
queue.offer("six");
System.out.println(queue);
/*
* poll方法是出队操作
* 获取队首元素后该元素即从队列中
* 被删除
*/
String str = queue.poll();
System.out.println(str);
System.out.println(queue);
/*
* peek是引用队首元素,元素不做出队
* 操作
*/
str = queue.peek();
System.out.println(str);
System.out.println(queue);
/*
* 遍历队列
* 使用迭代器遍历,元素不会因此被队列
* 删除
*
*/
for(String s : queue) {
System.out.println(s);
}
System.out.println(queue);
/*
* 使用poll方法遍历队列
*/
while(queue.size()>0) {
String s = queue.poll();
System.out.println(s);
}
System.out.println(queue);
}}
/**
* 双端队列
* java.util.Deque接口
* Deque继承自Queue接口
* 双端队列是指队列两端都可以做进出队操作。
* 常用实现类:LinkedList
* @author Mr.Cui
*/
public class DequeDemo {
public static void main(String[] args) {
Deque<String> deque
= new LinkedList<String>();
deque.offer("one");
deque.offer("two");
// First 开始位置
deque.offerFirst("three");
//Last 末端位置
deque.offerLast("four");
System.out.println(deque);
String str = deque.poll(); //出队操作
System.out.println(str);
System.out.println(deque);
//从开头开始删除
str = deque.pollFirst();
System.out.println(str);
System.out.println(deque);
//从末端开始删除
str = deque.pollLast();
System.out.println(str);
System.out.println(deque);
}}
/**
* 栈结构
* 栈也可以保存一组元素,但是存取元素必须遵循
* 先进后出原则。
* Deque双端队列可以实现栈,并且为栈专门提供
* 了两个方法:push,pop
* 通常我们使用栈是为了实现"后退"这样等功能
* @author Mr.Cui
*
*/
public class StackDemo {
public static void main(String[] args) {
Deque<String> stack
= new LinkedList<String>();
//stack 后退输出 如123输出321
stack.push("one");
stack.push("two");
stack.push("three");
stack.push("four");
stack.push("five");
System.out.println(stack);
//remove,poll,pop,均表示删除
String str = stack.pop();
System.out.println(str);//删除元素
System.out.println(stack);//输出删除后的元素
}}
/**
* 集合有线程安全的实现。我们可以借助Collections
* 将现有的集合转换为一个线程安全的。
* @author Mr.Cui
*
*/
public class SyncDemo {
public static void main(String[] args) {
/*
* List中常用的实现类:
* ArrayList,LinkedList它们都不是
* 线程安全的。
*/
List<String> list
= new ArrayList<String>();
list.add("one");
list.add("two");
list.add("three");
System.out.println(list);
/*
* 将给定的集合转换为一个线程安全的
*/
list = Collections.synchronizedList(list);
System.out.println(list);
/*
* HashSet同样也不是线程安全的
*/
Set<String> set
= new HashSet<String>(list);
set = Collections.synchronizedSet(set);
System.out.println(set);
/*
* 文档上有说明一个事情:
* 即使是一个线程安全的集合,它也不同
* 迭代器遍历做互斥,所以这个操作要自行
* 维护。
*/
/*
* 队列也有并发安全的实现
* 阻塞队列
* BlockingQueue,BlockingDeque
* 阻塞队列内部使用双缓冲实现,在保证
* 并发安全的前提下解决了存取互斥问题
* 所以并发效率更好
*/
BlockingQueue<String> queue
= new LinkedBlockingQueue<String>();
queue.offer("one");
try {
//500是时间(毫秒),Time.MILLISECONDS是单位
queue.offer("two", 500, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
e.printStackTrace();
}
}}
/**
* 判断Map是否包含给定元素。
* 可以分别判断是否包含key和value
* boolean containsKey(Object k)
* boolean containsValue(Object v)
* @author Mr.Cui
*/
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);
/*
* 查看是否包含指定的key
*/
boolean ck = map.containsKey("语文");
System.out.println("包含key:"+ck);
boolean cv = map.containsValue(95);
System.out.println("包含value:"+cv);
}}
/**
* HashMap是查询速度最快的数据结构,内部使用
* 数组实现,它通过Key的hashcode值计算该元素
* 在数组中的下标位置,从而避免了遍历数组的操
* 作,从而查询不受元素多少影响。
*
* 由于Key的hashcode方法(决定其在HashMap内部
* 数组的位置)和equals方法(决定Key是否为重复)
* 直接影响HashMap是否会出现链表,对此这两个
* 方法在Object类中有明确的重写说明。
*
* 当一个HashMap内部出现链表时,会降低其查询
* 性能,应当尽量避免。而出现链表的情况在于:
* 当两个Key的hashcode值相同,而equals比较不
* 为true时就会形成。
*
* API手册中在Object类里说明了这两个方法的重
* 写规则:
* 1:成对重写
* 当我们需要重写一个类的equals方法时,就
* 应当连同重写hashcode方法
* 2:一致性
* 当两个对象的equals比较为true时,hashcode
* 方法返回的数字必须相等。反之则不是必须的,
* 但是应当尽量保证当两个对象hashcode值相同
* 时equals方法比较为true,否则在HashMap中
* 作为Key使用时会出现链表!
* 3:稳定性
* 当一个对象参与equals比较的属性值没有发生
* 过改变的前提下,多次调用hashcode方法返回
* 的数字应当相同
*
* @author Mr.Cui
*
*/
public class Key {
private int x;
private int y;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Key other = (Key) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
} }
/**
* java.util.Map
* Map 查找表,结构看起来像是一个多行两列的
* 表格。左列称为key,右列称为value。
* 所以Map总是以key-value对的形式保存元素。
* 并且总是根据key去获取对应的value.
* 对此我们经常将“查询条件”作为key,将要查询
* 的数据作为value进行保存。
*
* Map本身是一个接口,规定了Map操作的相关方法。
* 常用实现类:java.util.HashMap
*
* HashMap又称为散列表,哈希表
* 使用散列算法实现的Map,当今世界上查询速度
* 最快的数据结构,查询速度最快,查询速度最快!
*
* @author Mr.Cui
*/
public class MapDemo1 {
public static void main(String[] args) {
Map<String,Integer> map
= new HashMap<String,Integer>();
/*
* V put(K k,V v)
* 将给定的一组键值对存入到Map中
*
* Map有一个要求,即:key不允许重复,
* 是否重复是依靠key自身equals比较的
* 结果。
* 如果使用map中已有的key保存value,
* 则这个操作为替换value操作,那么
* 这时put方法会将被替换的value返回。
* 否则返回值为null。
*/
/*
* 如果value是一个包装类,那么接收时
* 应当避免直接用基本类型。因为这会
* 导致自动拆箱,若没有做替换操作,返
* 回的value为null时就引发了空指针异常
*/
Integer d = map.put("语文", 98);
System.out.println(d);
map.put("数学", 97);
map.put("英语", 96);
map.put("物理", 95);
map.put("化学", 98);
System.out.println(map);
d = map.put("语文", 55);
System.out.println(d);
System.out.println(map);
/*
* V get(Object key)
* 根据给定的key获取对应的value,若
* 给定的key不存在,则返回值为null
*/
d = map.get("数学");
System.out.println("数学:"+d);
/*
* int size()
* 获取Map中的元素个数,每组键值对算
* 一个元素
*/
int size = map.size();
System.out.println("size:"+size);
/*
* V remove(K k)
* 将给定的key所对应的键值对删除。
* 返回值为该key对应的value。
*/
d = map.remove("语文");
System.out.println(map);
System.out.println(d);
}}
/**
* Map的遍历
* 遍历Map有三种方式
* 1:遍历所有的key
* 2:遍历每一组键值对
* 3:遍历所有的value(相对不常用)
*
* @author Mr.Cui
*/
public class MapDemo2 {
public static void main(String[] args) {
Map<String,Integer> map
= new LinkedHashMap<String,Integer>();
map.put("语文", 98);
map.put("数学", 97);
map.put("英语", 96);
map.put("物理", 95);
map.put("化学", 98);
System.out.println(map);
/*
* 遍历所有的key
* Set keySet()
* 将当前Map中所有的key以一个Set集合
* 形式返回。遍历这个集合就等同于遍历
* 了所有的key
*/
Set<String> keySet = map.keySet();
for(String key : keySet) {
System.out.println("key:"+key);
}
/*
* 遍历每一组键值对
* Set entrySet()
*
* java.util.Map.Entry
* Entry的每一个实例用于表示当前Map中的
* 一组键值对。其中有两个常用的方法:
* getKey(),getValue()分别用于获取对应的
* key与value
*/
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);
}
/*
* 遍历所有的value
*/
Collection<Integer> values = map.values();
for(Integer value : values) {
System.out.println("value:"+value);
} }}