1. JAVA异常分类及处理
概念
如果某个方法不能按照正常的途径完成任务,就可以通过另一种路径退出方法。在这种情况下会抛出一个封装了错误信息的对象。此时,这个方法会立刻退出同时不返回任何值。另外,调用这个方法的其他代码也无法继续执行,异常处理机制会将代码执行交给异常处理器。
1.1. 异常处理方式
-
抛出,抛给调用者
-
try catch 捕获异常针对性处理
2. Java反射
package com.tedu.fanshe;
public class Person {
private String name;
private int age;
public Person() {
}
public Person(String name,int age){
this.name =name;
this.age=age;
}
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 void Test(){
System.out.println("无参测试方法");
}
public void Test(String name,int age){
System.out.println(name+"带参测试方法");
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
package com.tedu.fanshe;
public class Student extends Person{
private boolean score;
public boolean getScore() {
return score;
}
public void setScore(boolean score) {
this.score = score;
}
}
package com.tedu.fanshe;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception {
package com.tedu.fanshe;
public class Test3 {
public static void main(String[] args) throws Exception {
/**
* 得到类对象
*/
Class c1 = Class.forName("com.tedu.fanshe.Person");
Class c2 = Person.class;
Class c3 = "com.tedu.fanshe.Person".getClass();
Class c4 = new Person().getClass();
/**
* 反射获取对象
*/
Object o1 = c1.newInstance();//默认使用无参
Constructor con1 = c1.getConstructor(String.class,int.class);
Object o2 = con1.newInstance("小明",18); //带参构造方法
/**
* 操作反射得到的对象
*/
Person p = (Person)o1;
p.getAge();
p.getName();
/**
* 反射获取属性对象
*/
//Field f1 = c1.getField("name");//获取公有属性
Field f2 = c1.getDeclaredField("name");//获取声明过的属性
f2.setAccessible(true);//允许访问私有成员
/**
* 反射操作属性
*/
f2.set(o1, "敬仰"); //为name属性赋值
Object object = f2.get(o1);//获取name的值
System.out.println(o1);
System.out.println(o2);
/**
* 反射获取方法对象
*/
Method m1 = c1.getMethod("Test", String.class,int.class);
Method m2 = c1.getMethod("Test");
/**
* 反射操作方法
* invoke: 唤醒
*/
Object invoke1 = m1.invoke(o1, "小张",19);
m2.invoke(o1);
}
}
3. Java注解
概念 : JDK1.5后新特性,用来说明程序的
生产文档
cmd——> javadoc xxx.class
3.1. 元注解: 用于描述注解的注解
@Target
描述注解能够作用的位置
@Retention
描述注解被保留的阶段
@ Documented
描述注解是否被抽取到api文档中
@Inherited
描述注解是否被子类继承,子类继承父类后也会被注解修饰
3.2. 反射获取注解信息
package zhujie;
public class Demo1 {
public void show(){
System.out.println("demo2----show---");
}
}
package zhujie;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.lang.model.element.Element;
/**
* 描述需要执行的类名,方法名
*
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface properties {
String className();
String methodName();
}
package zhujie;
import java.lang.reflect.Method;
@properties(className="zhujie.Demo1",methodName="show")
public class ReflectTest {
public static void main(String[] args) throws Exception{
//1.解析注解
//1.1获取该类的字节码文件对象
Class<ReflectTest> c = ReflectTest.class;
//2. 获取上边的注解对象
//其实就是在内存中生成了一个该注解接口的子类实现对象
properties an = c.getAnnotation(properties.class);
//3.调用注解对象中定义的抽象方法,获取返回值
String className = an.className();//zhujie.Demo1
String methodName = an.methodName();//show
/*public class propertieslmpl implements properties{
String className(){
return "zhujie.Demo1";
}
String methodName(){
return "show";
}
}
*/
Class<?> c2 = Class.forName(className);
Method m = c2.getMethod(methodName);
m.invoke(c2.newInstance());
}
}
4. Java内部类
内部类的作用: 防止类名冲突,实现多继承
4.1. 静态内部类
package base;
/**外部类*/
public class Out extends Demo1{
private static String name="waibu";
private int age;
static int a= 10;
void print(){System.out.println("Out--->print");}
public static class Inner extends Demo2{
int a= 20;
/**静态内部类可以访问外部类所有的静态 变量及方法,即使私有*/
void print(){System.out.println(name);}
public void Test(){
System.out.println(Out.a);
System.out.println(a);
print();
}
}
public static void main(String[] args) {
/**
* 静态内部类也叫做嵌套类,可以单独拿出使用
*/
Inner inner = new Inner();
inner.Test();
}
}
4.2. 成员内部类
定义在类内部的非静态类,就是成员内部类。成员内部类不能修饰静态方法和静态变量
package base;
/**外部类*/
public class Out extends Demo1{
private static String name;
private int age;
int a= 10;
void print(){System.out.println("Out--->print");}
/**
* 内部类可以调用外部类的所有属性、方法
*/
public class Inner extends Demo2{
int a= 20;
void print(){System.out.println("Inner--->print");}
public void Test(){
/**获取外部类的资源*/
System.out.println(Out.this.a);
Out.this.print();
System.out.println(a);
print();
}
}
public static void main(String[] args) {
Inner inner = new Out().new Inner();
inner.Test();
}
}
4.3. 局部内部类
定义在方法中的类,就是局部内部类
package base;
/**
* 局部内部类: 方法里面的内部类
* 1. 只能在方法里面时候,出了方法体就不可见
* 2. 局部内部类只能向上转型为父类或者接口类型才能对外可见
*
*/
public class Test {
public Her fun(){
class Out implements Her{
@Override
public void test() {System.out.println("Out--->Test()");}
}
return new Out();
}
public static void main(String[] args) {
Test t2 = new Test();
Her her = t2.fun();//用方法创建接口对象
her.test();
}
}
package base;
public interface Her {
int i=1;
public void test();
}
4.4. 匿名内部类
package base;
public class Test {
/**
* 匿名内部类 : 即使类也是对象
* 装饰者模式
*/
public Her fun(){
return new Her(){
public void test(){
System.out.println("her-->test()");
}
};
}
/** lambda*/
Her h = () -> {System.out.println("lambda");};
public static void main(String[] args) {
new Test().fun().test();
new Test().h.test();
}
}
5. Java泛型
package fanxing;
public class generic<T> {
private T key;
public generic(T key){
this.key = key;
}
public T getKey(){
return key;
}
}
package fanxing;
public class Test {
public static void main(String[] args) {
/**
* 泛型类在创建对象的时候,来指定操作的具体数据类型
*/
generic<String> g = new generic<>("hello");
String key = g.getKey();
System.out.println(key);
/**
* 如果不指定泛型,那么类型就是Object类型
*/
generic g2 = new generic("你好");
/**
* 泛型类不支持基本数据类型
*/
//generic<int> g3 = new generic<>(3);
/**
* 同一泛型类,根据不同的数据类型创建的对象,本质上是同一类型
*
*/
generic<Integer> g4 = new generic<>(10);
System.out.println(g.getClass()==g4.getClass());//true
}
}
5.1. 泛型类
package fanxing3;
public class Parent<E> {
private E value;
public E getValue(){
return value;
}
public void setValue(E value){
this.value = value;
}
}
package fanxing3;
/**
* 泛型类派生子类,子类也是泛型类,那么子类的泛型标示要和父类一致
*/
public class ChildFirst extends Parent<Object> {
@Override
public Object getValue() {
return super.getValue();
}
}
package fanxing3;
/**
* 父类明确类型
*/
public class ChildFirst2<T> extends Parent<T> {
@Override
public T getValue() {
return super.getValue();
}
}
5.2. 泛型方法
5.3. 类型通配符
package fanxing5;
public class Box<E> {
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
package fanxing5;
public class Test {
public static void main(String[] args) {
Box<Number> box1 = new Box<>();
box1.setFirst(100);
showBox(box1);
}
/*
public static void showBox(Box<Number> box){
Number first = box.getFirst();
System.out.println(first);
}
public static void showBox(Box<Integer> box){
Number first = box.getFirst();
System.out.println(first);
}
*/
/**
* 泛型通配符
*/
public static void showBox(Box<?> box){
Object first = box.getFirst();
System.out.println(first);
}
}
5.4. 类型消除
5.5. 泛型数组![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/06524df3253325aa5cfa66e13337190b.png)
声明泛型数组引用
package fanxing6;
import java.util.ArrayList;
import java.util.Arrays;
public class fanxingArray2 {
public static void main(String[] args) {
ArrayList<String>[] strList = new ArrayList[5]; //数组中的元素是动态数组
ArrayList<String> strList2 = new ArrayList<>();
strList2.add("abc");
System.out.println(strList2); //[abc]
strList[0]=strList2;
String s = Arrays.toString(strList);
System.out.println(s);//[[abc], null, null, null, null]
}
}
通过反射创建泛型数组
package fanxing6;
import java.lang.reflect.Array;
public class Fruit<T> {
private T[] array;
@SuppressWarnings("unchecked")
public Fruit(Class<T> clz,int length){
//通过Array.newInstance创建泛型数组
array = (T[]) Array.newInstance(clz, length);
}
public void put(int index, T item){
array[index] = item;
}
public T get (int index){
return array[index];
}
public T[] getAll(){
return array;
}
}
package fanxing6;
import java.util.Arrays;
@SuppressWarnings("all")
public class Test {
public static void main(String[] args) {
Fruit fruit = new Fruit(String.class,10);
fruit.put(0, "猫");
fruit.put(1, "苟");
fruit.put(2, "蛇");
String string = Arrays.toString(fruit.getAll());
System.out.println(string);
}
}
6. Java序列化
序列化就是把对象改成二进制的过程,可以保存到磁盘或者进行网络传输
- java.io.Serializable
- java.io.Externalizable
- ObjectInputStream
- ObjectOutputStream
6.1 如果某个变量不希望实现序列化?
变量声明成静态变量 static
变量声明成静态变量 transient
6.2 序列化的作用
- 方便传输,速度快,还很安全,调用方反序列化即可拿到传输前最原始的java对象,常用于不同进程之间的对象传输
- 方便存储,不管是存储成文件还是数据库,都行,存储为文件,下回要用可以直接反序列拿到对象
6.3 UID值的作用
用于判断序列化文件是否已经失效(过期)。序列化的时候会把这个ID写到文件里。读的时候会把这个ID和代码里的ID比较,如果不一致,表示文件里的已经失效
不写会有什么问题?
不写的话,序列话的时候,JVM会帮你动态的生成一个。这个动态生成的算法可能在不同的虚拟机里不一样,也就是不同的环境下生成的可能不同。这就会有一个问题,你序列化产生的文件,别人读的时候会 InvalidClassException
7. Java拷贝
在Java语言中,当我们需要拷贝一个java对象的时候,常见的会有两种方式的拷贝: 浅拷贝与深拷贝。
需要拷贝的对象需要实现Cloneable接口,重写clone()方法
7.1 浅拷贝
说明:
为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?
在运行时刻,Object中的clone()识别出你要复制的是哪一个对象.,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象
继承自Java.lang.Object类测clone()方法时浅复制
浅拷贝: 只复制对象中的基本类型,,而引用类型不复制,它指向的还是原来的对象
package Cpoy;
public class Test01 {
public static void main(String[] args) throws CloneNotSupportedException {
Stu s= new Stu();
s.setAge(20);
s.setName("邓圣");
Stu s2 =(Stu)s.clone();
System.out.println(s2.getAge());//说明被复制对象的所有变量(基本数据类型)都含有与原来的对象相同的值
System.out.println(s2.getName());
System.out.println("==========================");
System.out.println(s.getName().equals(s2.getName())); //true,说明没有创建新的对象
//s2.setName("黄振"); //指向了一个新的对象
//System.out.println(s2);
/**
* 对任何的对象x,都有x.clone() != x
*/
System.out.println(s==s2);//false,克隆对象与原对象不是同一个对象
/**
* 对任何的对象x,都有x.clone().getClass() == x.getClass(); true
*/
System.out.println(s2.getClass()==s.getClass());//克隆对象与原对象类型相同
System.out.println(s.clone().equals(s2)); //克隆对象与原对象不指向同一内存地址
}
}
class Stu implements Cloneable{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Stu [age=" + age + ", name=" + name + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
}
7.2 深拷贝
深拷贝: 复制对象中的基本类型和引用类型
package Cpoy;
public class Test02 {
public static void main(String[] args) throws CloneNotSupportedException {
Teacher t = new Teacher();
t.setAge(20);
t.setName("邓圣");
Stu2 s = new Stu2();
s.setId(01);
s.setUrl("127.0.0.1");
s.setTeacher(t);
Stu2 s2 = (Stu2) s.clone();
System.out.print("修改之前的值: ");
System.out.println(s);
/**
* 同过s2对象来修改Stu2中的引用变量Teacher
*/
s2.getTeacher().setName("黄老板");
System.out.print("修改之后的值: ");
System.out.println(s);
System.out.println(s2);//指向了新的对象,说明拷贝了Teacher类型
/**
* 说明: 被引用类型不会复制,只会复制八大基本类型
*/
/**
* 思考如何通过clone实现深复制
* 我们在复制Stu2时,同时也复制Teacher
*/
}
}
class Teacher implements Cloneable{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Teacher [age=" + age + ", name=" + name + "]";
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
class Stu2 implements Cloneable{
private int id;
private String url;
private Teacher teacher;
/*浅拷贝
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
*/
/**
* 深拷贝,拷贝了引用类型
*/
@Override
public Stu2 clone() throws CloneNotSupportedException {
/*Stu2 stu2 = (Stu2)super.clone();
stu2.setTeacher((Teacher)stu2.getTeacher().clone());
返回的Stu2对象中,封装了一个新的Teacher()
return stu2;*/
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try ( ObjectOutputStream oos = new ObjectOutputStream(byteArrayOutputStream);){
oos.writeObject(this);
} catch (IOException e) {
e.printStackTrace();
}
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
try ( ObjectInputStream ois = new ObjectInputStream(byteArrayInputStream);){
Stu2 objcet = (Stu2)ois.readObject();
return objcet;
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return "Stu2 [id=" + id + ", url=" + url + ", teacher=" + teacher + "]";
}
}
8. JavaIO
绝对路径 | 是一个完整的路径,例如:C:\\Users\\a.txt |
相对路径 | 是一个简化的路径,相对指的是相对于当前项目的根目录,如果使用当前项目的根目录,路径可以简化书写 |
File类常用方法
public String getAbsolutePath(),返回此File的绝对路径名字符串 |
public String getPath(),将此File转换为路径名字符串 |
public string getName(),返回由此File表示的文件或目录的名称 |
public long length(),返回由此File表示的文件的长度 |
public boolean exists(),此File表示的文件或目录是否实际存在 |
public boolean isDirectory(),此File表示的是否为目录 |
public boolean isFile(),此File表示的是否为文件 |
public boolean createNewFile(),当且仅当具有该名称的文件尚不存在时,创建一个新的空文件 |
public boolean delete(),删除由此File表示的文件或目录 |
public boolean mkdir(),创建由此File表示的目录 |
public boolean mkdirs(),创建由此File表示的目录,包括任何必需不存在的父目录 |
public String list(),返回一个String数组,表示该File目录中所有子文件或目录 |
public File[] listFiles(),返回一个File数组,表示该File目录中所有的子文件或目录 |
什么是IO
数据的传输,可以看做是一种数据的流动,按照流动的方向,以内存为基准,分为输入input
和输出output
,即流向内存是输入流,流出内存的输出流。
输入流 | 把数据从其他设备上读取到内存中的流 |
输出流 | 把数据从内存中写出到其他设备上的流 |
输入流 | 输出流 | |
字节流 | 字节输入流 InputStream | 字节输出流 outputStream |
字符流 | 字符输入流 Reader | 字符输出流 Writer |
java.ioFileOutputStream 文件字节输出流
把内存中的数据写入到文件中
FileOutputStream(String name) | 创建一个具有指定名称的文件中写入数据的输出文件流 |
FileOutputStream(File file) | 创建一个向指定File对象表示的文件中写入数据的文件输出流 |