泛型:是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
一提到参数,最熟悉的就是方法定义时有形参,然后调用此方法是传递实参。那么参数化类型怎么理解? 就是将类型由原来的具体的类型参数化,然后再使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口
泛型定义格式:<类型>:指定一种类型的格式,这里的类型可以看成是形参
<类型1,类型2...>:指定多种类型格式,多种类型之间用逗号隔开,这里的类型可
以看成是形参
将来具体调用时候给定的类型可以看成是实参,并且实参的类型之恶能是引用数据
类型
泛型的好处:把运行时期的问题提前到了编译期间
避免了强制类型转换
泛型类:格式:修饰符 class类名<类型>{}
例:public class Generic<T>{}
此处T可以随便写为任意表示,常见的如T、E、K、V等 形式的参数常用于表示泛型
泛型方法:格式:修饰符<类型>返回值类型 方法名(类型 变量名){ }
例:public <T> void show(T t){ }
泛型接口:泛型接口定义格式:修饰符interface 接口名<类型>{ }
例:public interface Generic<T>{ }
类型通配符:<?>
List<?>:表示元素类型未知的List ,它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
如果我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限
类型通配符上限:<?extends 类型>
List<? extends Number>:他表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,也可以指定类型通配符的下限
类型通配符下限;<?super 类型>
List<?super Number>:它表示的类型是Number或者其父类型
可变参数:又称参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
格式:修饰符 返回值类型 方法名 (数据类型... 变量名)
例;public static int sum (int...a){ }
其中a为数组
例: public static int sum (int b ,int...a){ }一个方法有多个参数,包含可变参数时,可变参数放在最后
可变参数的使用:Arrays工具中有一个静态方法; public static <T>List<T>asList(T a):返回有指定数组支持的固定大小的列表(返回的集合不能做增删操作,可以做修改操作)
List接口中有一个静态方法:public static <E>List<E> of(E...elements):返回包含任意数量元素的不可变列表(返回的集合不能做增删改操作)
Set接口中有一个静态方法:public static <E>Set<E> of(E...elements):返回一个包含任意数量元素的不可变集合(在给元素的时候不能给重复的元素;返回的集合不能做增删操作,没有修改的方法)
map集合概述:Interface Map<K,V> K:键的类型;V:值的类型
将键映射到值的对象:不能包含重复的键:每个键可以映射到最多一个值
举例:学生的学号和姓名
19407020619 小李
创建Map集合的对象
多态的方式
具体的实现类HashMap
Map<String,String> map = new HashMap<String,String>();
//将指定的值与该映射中的指定键为相关联 V put (K key,V vslue)
map.put("19407020616","小李");
hash保证键的唯一性
V put(K key,V value) 添加元素
V remove(Object key) 根据键删除键值对元素
void clear() 移除所有的键值对元素
boolean containsKey(Object key) 判断几个中是否包含指定的键
boolean containsValue(Object value) 判断集合是否包含指定的值
boolean isEmpty() 判断集合是否为空
int size() 集合的长度,也就是集合中键值对的个数
map集合的获取功能
V get(Object key) 根据键获取值
set<K> keySet() 获取所有键的集合
Collection<V> values() 获取所有值的集合
Set<Map.Entry<K,V>>entrySet() 获取所有键值对对象的集合
(get key()获取键 get value()获取值)
Map集合的遍历
Set<String> keySet = map.keySet();
for(String key : keySet){
String vaslue = map.get(key);
System.out.println(key+","+value);
}
方式2
Set<Map.Entry<Sting,String>> entrySet = map.entrySet();
for(Map.Entry<Sting,String> en : enteySet){
System.out.println( en.getKey()+","en.getValue());
}
ArrayList集合存储HashMap集合并遍历
for(HashMap<String,String> hm : array){
Set<String> keySet = hm.keyset();
for(String key : keyset){
String value = hm.get(key);
System.out.println(key+","+value);
}
}
HashMap集合存储ArrayList集合并遍历
Set<String> keySet = hm.keySet();
for(String key : keySet){
ArrayList<String> value = hm.get(key);
for(String s : value){
System.out.println(s)
}
}
Collections:针对集合操作的工具类
Collections类的常用方法
public static <T extens Comparable<?super T>> void sort(List<T>list):将指定的列表按升序排列
pubilc static void reverse(List<?>list):反转指定列表中元素的顺序
public static viod shuffle(List<?>list):使用默认的随机源随机排列指定的列表
Collections.sort(list);
Collections.reverse(list);
Collections.shuffle(list);
File类
File:是文件和目录路径的抽象表示
文件和目录是可以通过File封装成对象的
对于File,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的,将来是要通过具体的操作来把这个路径的内容转换为具体存在的
File(String pathname) 通过将给定的路径名字符串转换为抽象路径名来创建新的File实例
File(String parent,String child) 从父路径名字符串和子路径名字符串创建新的File实例
File(File parent,String child) 从父抽象路径名和子路径名字符串创建新的File实例
File类创建功能
public boolean createNewFile() 档具有该名称的文件不存在时,创建一个由该抽象路径名命名的新空文件(如果文件不存在,则创建文件并返回ture,若存在,不创建文件并返回false)
public boolean mkdir() 创建由此抽象路径名命名的目录(如果目录不存在,则创建文件并返回ture,若存在,不创建文件并返回false)
public boolean mkdirs() 创建由此抽象路径名命名的的目录,包括任何必须但不存在的父目录(如果目录不存在,则创建文件并返回ture,若存在,不创建文件并返回false)
File类判断和获取功能
public boolean isDirectory() 测试此抽象路径名表示的File是否为目录
public boolean isFile() 测试此抽象路径名表示的File是否为文件
public boolean exists() 测试此抽象路径名表示的File是否存在
public String getAbsolutePath() 返回此抽象路径名的绝对路径名字符串
public String getPath() 将此抽象路径名转换为路径名字符串
public String getName() 返回由此先后向路径名表示的文件或目录的名称
public String[] list() 返回此抽象路径名表示的目录中的文件和目录的名称字符串数组
public File[] listFiles() 返回此抽象路径名表示的文件和目录的File对象数组
File类的删除功能
public boolean delete() 删除由此抽象路径名表示的文件或目录
绝对路径和相对路径的区别
绝对路径:完整的路径名,不需要任何其他信息就可以定位它所表示的文件,例如:E:\\object\\java.txt
相对路径:必须使用取自其他路径名的信息进行解释,例如:idea\\java.txt
在删除目录时,若该目录下有文件,则不能直接删除成功,只有先删除文件才能删除目录。
递归:指的是方法定义中调用方法本身的现象
//第一个月一只,第二个月一只,第三个月两只,第四个月三只...
//第n个月有f(n)个兔子
//第n-1个月有f(n-1)个兔子
//第n-2个月有f(n-2)个兔子
public static int f(int n){
if(n==1||n==2){
return 1;
}else{
return f(n-1) + f(n-2);
}
}
递归解决问题思路:把一个复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算
递归解决问题,要找到两个内容:
1.递归出口:否则会出现内存溢出
2.递归规则:与原问题相似的规模较小的问题
字节流:
流:是一种抽象概念,是对数据传输的总称,也就是说数据在设备间的传输称为流,流的本质是数据传输
IO流:就是用来处理设备间数据传输问题的
常见应用:文件复制;文件上传;文件下载
IO流分类:按照数据的流向
输入流:读数据
输出流:写数据
按照数据类型来分
字节流
字节输出流;字节输入流
字符流
字符输出流;字符输入流
一般,IO流分分类是按照数据类型来分的。
这两种流在什么情况下使用?
如果数据通过window自带的记事本软件打开,我们还可以读懂里面的内容,就使用字符流,否则使用字节流。如果你不知道该使用哪种类型的流,就是用字节流
字节流写数据
Inputstream:这个抽象类时表示字节输入流所有类的超类
outputstream:这个抽象类时表示字节输出流所有类的超类
子类名特点:子类名成都是以其父类名作为子类名的后缀
FileOutputStream:文件输出流用于将数据写入File
FileOutputStream(String name):创建文件输出流以指定的名称写入文件
FileOutputStream fos = new FileOutpuutStream("Object\\test.txt");
/*它做了三件事情,
1.调用系统功能创建文件
2.创建了字节输出流对象
3.让字节输出流对象指向创建好的文件
*/
//void write(int b)将指定的字节写入此文件输出流
test.write(97);
//记事本打开是a
test.write(57);
//记事本打开是9
//最后都要释放资源
//void close() 关闭此文件输出流并释放与此流相关联的任何系统资源
test.close();
使用字节输出流写数据的步骤:
创建字节输出流对象(调用系统功能创建了文件,创建字节输出流对象,让字节输出流对象指向文件)
调用字节输出流对象的写数据方法
释放资源(关闭此文件输出流并释放与此流相关联的任何系统资源)
字节流写数据的3种方式
void write(int b) 将指定的字节写入此文件输出流,一次写一个字节数据
void write(byte[] b) 将b.length字节从指定的字节数组写入此文件输出流,一次写一个字节数组数据
void write(byte[] b,int off,int len)将len字节从指定的字节数组开始,从偏移量off开始写入此文件输出流一次写一个字节数组的部分数据
byte[] getBytes() 返回字符串对应的字节数组
byte[] b = "abcde".getBytes;
字节流写数据的两个小问题
1.字节流写数据如何实现换行
windows:\r\n
linux:\n
mac:\r
bos.write("/n".getBytes);
2.字节流写数据如何实现追加写入
public FileOutputStream(String name,boolean append);
创建文件输出流以指定的名称写入文件,如果第二个参数为true,则字节将写入文件末尾而不是开头
字节流写数据加入异常处理
finally:在异常处理时提供finally块来执行所有清除操作。不如说IO流中的释放资源
特点:被finally控制的语句一定会执行,除非JVM退出
try{
可能出现异常的代码;
}catch(异常类名 变量名){
异常的处理代码;
}finally{
执行所有清除操作;
}
字节流读数据(一次读一个字节数据)
FileInputStream(String name):通过打开与实际文件的连接来创建一个FileInputStream,该文件由文件系统中的路径名name命名
使用字节输入流读数据的步骤:
1.创建字节输入流对象
2.调用字节输入流对象的读数据方法
3.释放资源
int read() 从该输入流读取一个字节的数据
FileInputSream fis = new FileInputStream("Object\\test.txt")
int by;
while((by=fis.read())!=-1){
System.out.print((char)by)
}
fis.close;
int read(byte[] b) 从该输入流读取一个数组的数据
FileInputSream fis = new FileInputStream("Object\\test.txt");
FileOnputSream fos = new FileOnputStream("E\\test.txt");
byte[] bys = new byte[1024];
int len;
while((len=fis.read(bys))!=-1){
fos.write(bys,0,len);
}
fis.close;
fos.close;
new String(bys) 将字符数组转换为字符串
String (byte[] bytes,int offset,int length) 只转换 off- len的字符数组
字节缓冲流:
BufferOutputStream:该类实现缓冲输出流,通过设置这样的输出流,应用程序可以向底层输出流写入字节,而不必为写入的每个字节导致底层系统调用
BufferedInputStream:创建BufferedInputStream将创建一个内部缓冲区数组,当从流中读取或跳过字节时,内部缓冲区将根据需要从所包含的输入流中重新填充,一次很多字节
构造方法:
字节缓冲输出流:BufferOutputStream(OutputStream out)
字节缓冲输入流:BufferedInputStream(InputStream in)
为什么构造犯法需要的是字节流,而不是具体的文件或者路径?
字节缓冲流仅仅提供缓冲区,而真正的读写数据还得依靠基本的字节流对象进行操作
BufferedInputStream bis =new BufferedInputStream(new FileInputStream("....."));
BufferedOnputStream bos =new BufferedOnputStream(new FileOnputStream("....."));
int by;
while((by=bis.read())!=-1){
bos.write(by);
}
bis.close;
bos.close;
BufferedInputStream bis =new BufferedInputStream(new FileInputStream("....."));
BufferedOnputStream bos =new BufferedOnputStream(new FileOnputStream("....."));
byte[] bys = byte[1024];
int len;
while((len = bos.read(bys))!=-1){
bos.write(bys,0,len);
}
bis.close;
bos.close;
一个汉字存储:
GBK编码,占用2个字节
UTF-8编码,占用3个字节
由于字节流操作中文不是很方便,所以java提供字符流
字符流=字节流+编码
用字节流复制文本文件时,文本文件也会有中文,但是没有问题,原因是最终底层操作会自动进行字节拼接城中文,如何识别中文?
汉子在存储的时候,无论选择哪一种 编码存储,第一个字节都是负数,
编码表:GBK:最常用的中文编码表,实在GB2312标准基础上的扩展规范,使用了双字节编码方案,共收录了21003个汉字,完全兼容G2312标准,同时支持繁体汉字以及日韩汉字等
Unicode字符表:为表达任意语言的任意字符而设计的,是业界的一种标准,也成为同意吗、标准万国码。他最多使用四个字节的数字来表达每个字母、符号,或者文字。有三种编码方案:UTF-8、UTF-16、UTF32。最为常用的是UTF-8编码
UTF-8编码:可以用来表示Unicode标准中的任意字符,他是电子邮件、网页以及其他存储或传送文字的应用中,优先采用的编码。互联网工程工作小组要求所有互联网协议都必须支持UTF-8编码。他是用1-4个字节为每个字符编码
字符串中的编码解码问题
编码:
byte[] getBytes():使用平台的默认字符集将该String编码为一系列字节,将结果储存到新的字节数组中
byte[] getBytes(String charseName):使用指定的字符集将该String编码为一系列字节,将结果储存到新的字节数组中
解码:
String(byte[] bytes):通过使用平台的默认字符集解码指定的字节数组来构造新的String
String(byte[] bytes,String charseName)通过指定的字符集编码指定的字节数组来构造新的String
String s = "中国";
byte[] bys = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys));
String ss = new String(UTF-8);
System.out.println(ss);
字符流中的编码解码问题
字符流抽象基类
Reader:字符输入流的抽象类
Writer:字符输出流的抽象类
字符流中和编码解码相关的两个类
InputStreamReader
OutputStreamWriter
字符流写数据的五种方式
void write(int c) 写一个字符
void write(char[] cbuf) 写入一个字符数组
void write(char[] cbuf, int off,int len) 写入字符数组的一部分
voidwrite(String str) 写入一个字符串
void write(String str,int off,int len) 写一个字符串的一部分
public static void main(String[] args) throws IOException {
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("untitled1//osw.txt"));
char[] chs = {'a','b','c','d','e'};
osw.write(chs,0,3);
osw.flush();
}
void flash(); 刷新流,还可以继续写数据
close(); 关闭流,释放资源,但是在关闭之前会先刷新流,一旦关闭,就不能再写数据
字符流读数据的两种方式
int read() 一次读一个字符数据
int read(char[] cbuf) 一次读一个字符数组数据
public static void main(String[] args) throws IOException {
InputStreamReader isw = new InputStreamReader(new FileInputStream("untitled1//osw.txt"));
int ch;
while((ch=isw.read())!=-1){
System.out.print((char)ch);
}
isw.close();
}
public static void main(String[] args) throws IOException {
InputStreamReader isw = new InputStreamReader(new FileInputStream("untitled1//osw.txt"));
char[] chs =new char[1024];
int len;
while((len=isw.read(chs))!=-1){
System.out.println(new String(chs,0,len));
}
isw.close();
}
FileReader:用于读取字符文件的便捷类
FileReader(String fileName)
FileWriter:用于写入字符文件的便捷类
FileWriter(String fileName)
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("untitled1//copy.txt");
FileReader fr = new FileReader("untitled1//untitled1.java");
int ch;
while ((ch=fr.read())!=-1){
fw.write(ch);
}
fw.close();
fr.close();
}
public static void main(String[] args) throws IOException {
FileWriter fw = new FileWriter("untitled1//copy.txt");
FileReader fr = new FileReader("untitled1//untitled1.java");
int len;
char[] chs = new char[1024];
while ((len=fr.read(chs))!=-1){
fw.write(chs);
}
fw.close();
fr.close();
}
字符缓冲流:
BufferedWriter:将文本写入字符输出流,缓冲字符,以提供单个字符,数组和字符串的高校写入,可以指定缓冲区大小,或者可以接受默认大小。魔偶认知足够大,可用于大多数用途
BufferedReader:从字符输入流读取文本,缓冲字符,以提供字符,数组和行的高效率读取,可以指定缓冲区大小,或者可以使用默认大小。默认值足够大,可用于大多数用途
BufferedWriter(Writer out)
BufferedReader(Reader in)
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("untitled1//untitled1.java"));
BufferedWriter bw = new BufferedWriter(new FileWriter("untitled1//copy.txt"));
int ch;
while((ch=br.read())!=-1){
bw.write(ch);
}
bw.close();
br.close();
}
字符缓冲流特有功能
BufferedWriter:
void newLine(); 写一行行分隔符,行分隔符字符串由系统属性定义
BufferedResder:
public String readLine(); 读一行文字。结果包含行的内容的字符串,不包括任何行终止字符,如果流的结尾已经到达,则为null
public static void main(String[] args) throws IOException {
BufferedWriter bw = new BufferedWriter(new FileWriter("untitled1//copy.txt"));
BufferedReader br = new BufferedReader(new FileReader("untitled1//untitled1.java"));
String line;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
bw.close();
br.close();
}
IO流小结
字节流可以复制任意文件数据,有4种方式一般采用自己缓冲流一次读写一个字节数组的方式
字符流只能复制文本数据,有五种方式,一般采用字符缓冲流的特有功能