定义:参数化类型,给类型指定一个参数,然后在使用时再指定此参数具体的值,那样这个类型就可以在使用时再决定了;这种参数可以运用在类、接口、方法的创建中,被称为泛型类、泛型方法、泛型接口;
特点:
1、泛型如果没传,就默认Object;
2、使用带泛型的类创建对象时,两边的泛型必须一致;
3、只在编译阶段有效,编译时会自动去泛型化操作
4、泛型类型在逻辑上是多个不同类型,实际上都是相同的基本类型
好处:
1、为实现参数的任意化(缺点是要做强制类型转换)
2、编译时检查类型安全,所有强制转换都是自动和隐式的,提高代码的重用率
3、在编译期即可完成类型检查工作,并提出错误
4、简化开发,保证提高代码质量
使用:
泛型类:泛型用于类的定义中,传入的实参必须和泛型的参数类型相同;
class 类名称 <泛型标识:可以随便写任意标识号,标识指定的泛型的类型>{
private 泛型标识 /*(成员变量类型)*/
}
//当不传入泛型类型的实参时,方法或变量可以为任何类型
Generic generic = new Generic("111111");
Generic generic1 = new Generic(222222);
Log.d("泛型测试","key is " + generic.getKey());
Log.d("泛型测试","key is " + generic1.getKey());
泛型方法:判断一个方法是否为泛型方法,主要看返回值前有没有使用<>
public class Generic {
public T name;
public Generic(){}
public Generic(T param){
name=param;
}
public T m(){
return name;
}
public void m1(E e){ }
public T m2(T e){ }
}
m()方法不是泛型方法,m1()与m2()都是;
m2()方法中声明的类型T与类申明里面的那个参数T不是一个,也可以说方法中的T隐藏了类型中的T
泛型接口:未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中;
//定义一个泛型接口
public interface Generator {
public T next();
}
泛型通配符:
泛型通配符一般使用?代替具体的类型实参,可以把?看成所有类型的父类,是一种真实的类型
public void showKeyValue1(Generic> obj){
Log.d("泛型测试","key value is " + obj.getKey());
}
通配符上、下界:
上界:使用 extends T>格式,意思为需要T或T的子类,T为具体类型
public void printIntValue(List extends Number> list) {
for (Number number : list) {
System.out.print(number.intValue()+" ");
}
}
下界:使用 super T>格式,意思为需要T或T的父类,T为具体类型
public void fillNumberList(List super Number> list) {
list.add(new Integer(0));
list.add(new Float(1.0));
}
定义:在执行过程中发生中断执行程序端的指令流;异常就是在程序发生异常时,强制终止程序运行,并且将异常信息返回,有开发者觉得是否处理异常
产生原因:
1、java内部发生异常(Java虚拟机)
2、代码的错误产生异常
3、手动生成的异常,通过throw来生成
类型:
1、运行时异常:这些异常通常是由于一些逻辑错误产生的;常见:空指针异常、类型转 换异常、数组越界异常等
2、编译时异常 :必须处理,否则程序编译无法通过,常见:流传输异常、数据库操作异常等
处理:
1、try-catch;try用于监听异常,catch捕获处理异常,多个catch从上往下依次执行
try{
//程序代码
}catch(Exception e){
//catch块
}
2、try-catch-finally;try用于监听异常,catch捕获处理异常,finally总会被执行;
try{
//程序代码
}catch(Exception e){
//catch块
}finally{
......
}
在catch中遇到return时,仍然会先执行finally语句,再回来执行对应catch语句中的return语句;
当finally中存在return ,返回值会被return 覆盖掉
3、throw/throws,当处理不了时,在方法或语句上告诉调用者,这里有问题;如果一个方法没有捕获到检查性异常,那么该方法就必须使用throws关键字声明(声明抛出多个异常,之间使用逗号隔开),也可以在语句中使用throw关键字抛出一个异常
public static void test() {
int a = 520;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
public static void test() throws Exception {
int a = 520;
int b = 0;
if (b == 0) {
throw new Exception();
} else {
System.out.println(a / b);
}
}
throw和throws的区别:
throw:
用在方法声明后,跟的是异常类名
可以跟多个异常类名,用逗号隔开
表示抛出异常,由该方法的调用者来处理
throws表示出现异常的一种可能性,不一定会发生这些异常
throws:
用在方法体内,跟的是异常对象名
只能抛出一个异常对象名
表示抛出异常,由方法体内的语句处理
执行throw则一定抛出了某种异常
4、自定义异常
步骤:
1、创建自定义异常类
2、在方法中通过throw抛出异常
异常机制过程:
1、程序无法运行时,从当前环境中跳出
2、new一个异常对象,然后在异常位置终止程序,并且将异常从环境中返回
3、异常处理机制接管程序,并且查找可以继续执行程序的位置
流的本质是数据的传输对文件的处理,作用是为数据和目的地建立一个传输通道;
io模型设计是采用Decorator(装饰者)模式
输入流:读数据;输出流:写入数据。
字节流 |
字符流 |
|
输入流 |
InputStream |
Reader |
输出流 |
OutputStream |
Writer |
字节流:
一切文件数据(文本、图片、视频等)在存储时,都是以二进制数字的形式保存,都一个一个的字节,那么传输时一样如此。所以,字节流可以传输任意文件数据。
字符流:
就是在字节流的基础上加上编码,形成的数据流;因为字节流操作字符时,可能会有中文导致乱码,所以就在字节流的基础上引申出来了字符流。
File类是对文件系统中文件以及文件夹进行封装的对象,可以通过对象的思想来操作文件和文件夹
字符流和字节流的区别:
1、字节流在操作的时候本身不用缓存区的,是与文件直接对接的;而字符流操作时需要缓冲区。
2、使用字节流时,即使流没有关闭,最终也可以输出到文件;
3、使用字符流时,所有的内容保存在缓冲区,流关闭时 会强制性的将缓冲区内容写到文件中,如果没有关闭流,文件中就不会有内容输出。
字符流和字节流如何选择:
1、大多数情况下使用字节流会更好,因为大多数时候 IO 操作都是直接操作磁盘文件,所以这些流在传输时都是以字节的方式进行的(图片等都是按字节存储的)
2、如果对于操作需要通过 IO 在内存中频繁处理字符串的情况使用字符流会好些,因为字符流具备缓冲区,提高了性能
字符流和字节流的转化:
1、字节输入流转化为字符输入流(InputStreamReader):
public class Test {
public static void main(String[] args) throws IOException {
//1.定义输出文件路径
File file =
new File("d:"+File.separator+"Demo"+File.separator+"OutputStreamWriter.txt");
//判断目录是否存在
if(!file.getParentFile().exists()){
//创建文件目录
file.getParentFile().mkdirs();
}
//2.取得字节输出流
OutputStream outputStream = new FileOutputStream(file);
//3.将字节输出流转换为字符输出流
OutputStreamWriter out = new OutputStreamWriter(outputStream);
out.write("欢迎使用字节输出流转换字符输出流!");
//4.关闭流
out.close();
}
}
2、字节输出流转化为字符输出流(OutputStreamWrite):
File f = new File("c.txt");
FileOutputStream fos = new FileOutputStream(f);
OutputStreamWriter osw = new OutputStreamWriter(fos,"UTF-8");
缓冲区:
1、缓冲区就是一段特殊的内存区域,很多情况下当程序需要频繁地操作一个资源(如文件或数据库)则性能会很低,所以为了提升性能就可以将一部分数据暂时读写到缓存区,以后直接从此区域中读写数据即可,这样就显著提升了性。
2、对于 Java 字符流的操作都是在缓冲区操作的,所以如果我们想在字符流操作中主动将缓冲区刷新到文件则可以使用 flush() 方法操作。