Java技术整理(4)—— Java基础篇

1、Java异常分类及处理

异常处理是为了解决在程序处理时发生错误而无法退出的问题。

(1)异常分类

Object —— Throwable(所有错误或异常的超类)

  • Error: 是指 Java 运行时系统的内部错误和资源耗尽错误,应用程序并不会抛出该对象,如果出现这样的错误,尽量保证系统安全结束
  • Exception: Java 异常有两种异常类型,运行时异常、检查异常
    • RuntimeException: 例如 NullPointerException、ClassCastException,基本上都是程序设计者设计不合理才会产生的异常
    • CheckedException: 例如 IOException、SQLException,一般是外部错误,这种异常都发生在编译阶段,Java 编译器会强制程序捕获异常,即会出现要求你把这段可能出现异常的程序进行try…catch…,这类异常一般包括几个方面:
      • 试图在文件尾部读取数据
      • 试图打开一个错误格式的URL
      • 试图根据给定的字符串查找 class 对象,而这个字符串表示的类并不存在

(2)异常的处理方式

自然抛出异常有三种形式:throw、throws、系统自动抛出异常

捕获异常并处理是以 try…catch… 作为捕获异常并处理代码的结构

(3)throw 与 throws 的区别

  • 位置不同: throws 用在函数声明上,抛出的是异常类,并且可以抛出多个;throw 用在函数内,用来抛出异常对象
  • 功能不同:
    • throws用来声明异常,让调用者了解该功能可能出现的问题,预先给出处理方式;throw 抛出具体的问题对象,执行到throw,程序立即结束,跳转回调用者,并将具体的问题对象抛出调用者,即throw语句独立存在时,后续程序无法执行。
    • throws表示的是异常的可能性,并不一定会发生异常;throw 则一定会抛出确定的异常

2、Java 反射

(1)动态语言: 是指程序运行时可以改变其结构,即新的函数可以引进,已有的函数可以被删除等结构上的变化。
(2)反射机制的概念: Java中的反射机制是在运行状态中,对于任意一个类都能获取这个类所有的属性和方法,并且对于任意一个对象,都能调用它的任意一个方法。
(3)反射的应用场合: 编译时类型和运行时类型

  • 编译时类型: 由声明对象时实用的类型决定,并且无法获取具体方法,如Person person = new Student();,声明的是Person类型,但运行时是Student类型
  • 运行时类型: 由赋值对象的类型决定

当程序运行时可能会接收外部传入的对象,该对象在编译时类型为Object,但程序调用需要知道该对象的运行时类型,所以可以利用反射来获取该对象的类型以及类信息。

(4)反射API

反射 API 用来生成JVM中的类、接口或对象的信息。

  • Class类: 反射的核心类,可以获取类的属性、方法等信息。
  • Field类: java.lang.reflec 包中的类,表示类的成员变量,用来获取和设置类中的属性值
  • Method类: java.lang.reflec 包中的类,表示类的方法,用来获取类中的方法信息或调用方法
  • Constructor类: java.lang.reflec 包中的类,表示类的构造方法

(5)反射的步骤

  • 获取想要操作的Class对象
  • 调用Class类中的方法
  • 使用反射API操作这些信息

(6)获取Class对象的方法

  • 实例对象.getClass(): 是实例对象获取Class对象的方法
  • 类名.class: 是每一个类加载时,都会维护一个class 属性,class 属性中存储了该类的相关信息
  • Class.forName(): Class 类提供基于全路径获取Class对象的静态方法

(7)创建Class对象的方法

  • newInstence(): 这种创建方法要求 Class对象有默认的空构造器
  • Constructor的newInstance(): 这种创建方法要求先获取Constructor,因为需要确认Class对象具有构造器

3、Java注解

(1)概念: Annotation 是 Java 提供的一种对元程序中关联信息和元数据(metadata)的途径和方法;它是一种接口,程序可以通过反射来获取指定程序中的Annotation对象,通过Annotation对象来获取元数据信息。
(2)元注解: 元注解的作用是负责注解说明其它注解,JDK 5 定义了 4 个标准的 meta-annotation 类型。

  • @Target: 说明修饰的对象范围
    • packages
    • types: 类、接口、枚举、Annotation类型
    • 类型成员: 方法、构造方法、成员变量、枚举值
    • 方法参数
    • 本地变量: 如循环变量、catch参数
  • @Retention: 定义Annotation的生命周期
    • @SOURSE: 在源文件中有效
    • @CLASS: 在class文件中有效
    • @RUNTIME: 在运行时有效
  • @Documented: 描述-javadoc,用来描述其它类型的annotation应该被作为被标注的程序成员的公共API
  • @Inherited: 描述某个被标注的类型是被继承的,若该注解在某个类上,则这个类的子类也会继承父类拥有的注解

(3)注解处理器

注解处理器是用于注解读取与使用注解的核心程序。

实现注解处理器:

//1、创建注解处理器
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {
	public int id() default -1;
	public String name() default "";
	public String address default "";
}

//2、使用注解处理器
public class Apple{
	@FruitProvider(id=1,name="陕西红富士集团",address="陕西省西安市延安路")
	private String appleProvider;

	public void setAppleProvider(String appleProvider){
		this.appleProvider = appleProvider;
	}

	public String getAppleProviderO (
		return appleProvider;
	}
}

//3、注解处理器
public class FruitInfoUtil {
	public static void getFruitInfo(Class<?> clazz) {
		String strFruitProvicer = "供应商信息:";
		Field[] fields = clazz.getDeclaredFields(); //获取成员变量
		for (Field field : fields){
			FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);
			strFruitProvicer = "供应商编号:" + fruitProvider.id() + "供应商名称:" + fruitProvider.name() + "供应商地址:" +  fruitProvider.address();
			System.out.println(strFruitProvicer);
		}
	}
}


4、Java内部类

Java类中不仅可以定义变量和方法,还可以定义类,定义在类内部的类称为内部类,根据定义方式不同,内部类分为静态内部类、成员内部类、局部内部类、匿名内部类四种。

  • 静态内部类: 使用static关键字修饰的内部类,这种内部类可以与外部类共享所有的静态资源,通过使用外部类名.内部类名获得编译时类型。例如,HashMap类内部就有一个静态内部类Entry。
  • 成员内部类: 普通的内部类,这种类不能定义静态方法和变量(因为只有静态资源才属于类对象,并且JVM先加载静态资源,容易产生冲突)
  • 局部内部类: 定义在方法内部的类,充当临时对象进行存储。
  • 匿名内部类: 匿名内部类必须继承一个父类或只实现一个接口,同时也没有class关键字,通过new关键字直接生成一个对象的引用。

5、泛型

泛型是用来声明无法确定的对象类型,编译器会通过传入的值来确定对象类型。

(1)泛型方法

public static <E> void printArray(E[] inputArray){
	for(E element : inputArray) {
		System.out.printf("%s", element);
	}
}
  • : 表示该通配符代表T的所有子类
  • :表示该通配符代表T的所有父类

(2)泛型类

public class Box<T>{
	private T t;
	
	public void add(T t){
		this.t = t;
	}
	
	public T get(){
		return t;
	}
}

(3)类型通配符

类型通配符通常使用 ?来代替具体的类型参数,例如List 在逻辑上是所有List具有泛型约束的父类

(4)类型擦除

Java中的泛型基本上是在编译器层面的实现,在生成的字节码中是不存在泛型的,在编译时,自动将传入的数据类型覆盖到泛型使用的位置上,这样的过程叫类型擦除。


6、序列化

(1)序列化的作用: 序列化操作可以持久化对象及其状态到内存或者磁盘中
(2)序列化的存储: 序列化是将传入对象转为字节数组进行存储,但是序列化只关注其成员变量,而不关注静态资源
(3)序列化的使用场景: 持久化对象;网络传递对象等等…
(4)序列化的实现:

  • Java提供了 java.io.Serializable 接口,只要类实现接口,就可以被序列化
  • 利用ObjectOutputStream和ObjectInputStream进行序列化和反序列化
  • 利用writeObject和readObject实现自定义序列化策略

(5)反序列化的关键点——序列化ID:

  • 序列化ID: 虚拟机是否支持反序列化,不仅取决于类路径和功能代码是否一致,还取决于两个类的序列化ID是否一致

(6)序列化在子父类中的使用: 若子类实现序列化,而想要父类也能够序列化,那么父类必须也实现Serializable接口
(7)阻止某个变量不进行序列化: Java 提供了 Transient 关键字来声明变量不参与序列化过程,在反序列化时,对应的 trasient 变量则被初始化。


7、Java复制

Java 程序中若想要将一个对象复制给另一个对象,一共有三种方法:直接赋值、浅拷贝、深拷贝。

  • 直接赋值: 直接引用同一对象,从表面上看确实是复制了一个对象,但在内部依旧是同一个内存空间
  • 浅拷贝: 创建一个新对象,复制非静态字段到新对象,但若旧对象中有一个引用对象,则复制的是引用对象的地址,即直接赋值给新对象的引用对象变量。
  • 深拷贝: 创建一个新对象,将旧对象的所有资源打个包,创建一个副本提供给新对象,即两个成为结构相同,但存储地址不同的对象。(实现方式可以通过序列化与反序列化操作进行对象创建)

你可能感兴趣的:(java,python,开发语言)