基本概念

Java 是一门面向对象的编程语言,它有简单、面向对象、分布式、健壮、安全、跨平台等特点。以下是 Java 基础知识的一些重要概念和语法:

Java 类和对象:Java 是一门面向对象的语言,类是 Java 的基本组成单元,对象是类的实例化。类可以包含属性和方法,方法是类的行为。类是抽象的,对象是具体的。创建对象时需要使用 new 关键字。

Java 数据类型:Java 中有基本数据类型和引用数据类型。基本数据类型包括 boolean、byte、short、int、long、float、double 和 char;引用数据类型包括类、接口、数组等。

Java 控制流语句:Java 中的控制流语句包括 if-else、switch-case、for、while、do-while、break 和 continue 等。

Java 方法和函数:Java 方法是一段可重用的代码,可以被多次调用。方法可以接受参数和返回值,是一种封装和抽象的编程方式。函数是一种具有单一功能的方法,它只返回一个值。

Java 异常处理:Java 中的异常是程序运行时发生的错误或意外情况。Java 提供了 try-catch-finally 语句来捕获和处理异常。异常分为检查异常和非检查异常,非检查异常包括 RuntimeException 和 Error。

Java 输入输出:Java 中的输入输出使用流的概念来实现。Java 中有字节流和字符流两种类型,字节流适用于处理二进制数据,字符流适用于处理文本数据。输入输出可以使用 FileInputStream、FileOutputStream、BufferedReader、PrintWriter 等类来实现。

Java 线程:Java 中的线程是独立的执行单元,它可以同时执行多个任务。Java 提供了 Thread 类和 Runnable 接口来实现线程。线程的状态包括新建、就绪、运行、阻塞和终止等状态。线程同步可以使用 synchronized 和 Lock 机制来实现。

封装、继承和多态

封装、继承和多态是面向对象编程的三个基本特性。

封装(Encapsulation):封装是一种隐藏对象内部实现细节的机制,使对象更易于使用和维护。Java 中通过将属性和方法封装在类中来实现封装。使用访问修饰符(public、private、protected)控制属性和方法的访问级别,实现对外部的隐蔽。

继承(Inheritance):继承是一种复用现有代码的机制,可以从已有的类中派生出新的类。Java 中使用 extends 关键字实现继承。继承可以通过子类拓展父类的功能,并且可以重写父类的方法,实现多态。

多态(Polymorphism):多态是一种使程序具有灵活性的机制,使不同对象可以用相同的接口访问。Java 中的多态通过方法的重载(Overload)和方法的覆盖(Override)来实现。方法的重载是指在同一个类中定义多个同名方法,但是参数列表不同;方法的覆盖是指在子类中重写父类的方法,实现多态。

这三个特性在 Java 中是相互依存的,封装可以使继承和多态更加有效,继承可以为多态提供基础,多态可以使对象的使用更加灵活。了解和掌握这三个特性可以帮助 Java 开发者更好地设计和实现面向对象的程序。

重写和重载

在Java中,重载(Overload)和重写(Override)是两个常见的方法使用技术

重载(Overload)是指在同一个类中定义多个同名方法,但是参数列表不同。可以通过不同的参数类型、参数个数或者参数顺序来区分不同的方法。在调用时,Java会根据传入的参数类型、个数和顺序来匹配对应的方法。重载方法返回值类型和访问修饰符可以相同,也可以不同。重载方法不能只有访问修饰符或返回值类型不同,必须有不同的参数列表。

重写(Override)是指在子类中重写父类的方法。重写方法与被重写方法的方法名、参数列表和返回值类型都必须相同。重写方法的访问修饰符不能比被重写方法的更严格,即子类不能降低被重写方法的访问权限。同时,重写方法不能抛出比被重写方法更多的异常,但可以抛出与被重写方法相同的异常或其子类异常。

重载和重写是Java中常见的方法使用技术,通过这两种技术,可以提高程序的可读性和可维护性。在重载时,应该使用不同的参数列表来区分不同的方法;在重写时,应该保证重写方法与被重写方法具有相同的方法名、参数列表和返回值类型,保证程序的正确性。

类的加载过程

Java虚拟机在运行Java程序时,需要将程序所需要的类加载到内存中,这个过程就是类加载过程。

Java虚拟机将类的加载过程分为了三个步骤:加载(Loading)、链接(Linking)和初始化(Initialization)。

加载(Loading):是指将类的.class文件从磁盘或其他设备加载到内存中。类加载器首先根据类的全限定名查找该类的字节码文件,如果找到则读取该字节码文件,并且将其转换为虚拟机可以使用的内部数据结构,并且在内存中生成一个代表该类的Class对象。需要注意的是,一个类只会被加载一次,即使同一个类被多次加载,也只会生成一个Class对象。

链接(Linking):是指将类的二进制代码合并到JRE中。链接又可以分为三个阶段:

验证(Verification):是指检查字节码是否符合Java虚拟机规范。主要验证类的格式、语义和安全性,防止Java程序被恶意篡改。

准备(Preparation):是指为类的静态变量分配内存并设置默认初始值。静态变量是类的所有实例对象共享的,而且在类加载的时候就已经被初始化,所以需要在准备阶段为它们分配内存并设置初始值。

解析(Resolution):是指将类中的符号引用转换为直接引用。类中的方法调用、字段访问等操作都是使用符号引用来实现的,解析阶段会将符号引用转换为对应的内存地址。

初始化(Initialization):是指执行类构造器方法(<clinit>)的过程。类构造器方法是Java虚拟机自动生成的,用于初始化类的静态变量和其他静态代码块。在执行类构造器方法前,需要保证该类的所有父类都已经完成了初始化,否则会先触发父类的初始化。

类加载器(Class Loader)

类加载器(Class Loader)是Java虚拟机的重要组成部分之一,它负责将类的字节码文件(.class文件)加载到内存中,并且将其转换成Java虚拟机可以使用的Class对象。Java虚拟机自带了三种类加载器:

Bootstrap ClassLoader:也叫根类加载器,它是Java虚拟机的一部分,负责加载Java API类库中的核心类,比如java.lang包中的类。

Extension ClassLoader:也叫扩展类加载器,它是Java虚拟机的扩展机制的一部分,负责加载Java虚拟机的扩展类库,比如JAVA_HOME/jre/lib/ext目录下的类库。

System ClassLoader:也叫应用程序类加载器,它是负责加载应用程序中的类,它是Java虚拟机的默认类加载器,所有用户自定义的类都是由它来加载。

除了Java虚拟机自带的三种类加载器,Java还提供了一种特殊的类加载器,即自定义类加载器(Custom ClassLoader)。自定义类加载器可以根据应用程序的需求,从不同的源(如网络、数据库、动态生成的类等)加载类,它可以实现热部署、隔离加载、动态加载等功能,是Java中实现插件化架构的关键。

需要注意的是,类加载器使用的是委托机制,即当一个类需要被加载时,先会将这个请求委托给父类加载器去处理,如果父类加载器找不到该类,则会将请求委托给它的父类加载器去处理,直到委托到Bootstrap ClassLoader为止,如果Bootstrap ClassLoader还是找不到该类,则会将请求返回给子类加载器去处理。这种委托机制可以保证类的唯一性和安全性,同时也能够避免类的重复加载。

打破双亲委派

在一些特殊情况下,我们可能需要打破双亲委派机制,自定义类加载器加载一些系统类库中已经存在的类,或者加载某些需要独立升级的类等。为了实现这种需求,可以通过重写ClassLoader的loadClass方法来打破双亲委派机制。具体实现方式如下:

创建一个自定义类加载器,继承ClassLoader类。

重写loadClass方法,自己实现类的加载过程。在自定义类加载器的loadClass方法中,首先判断需要加载的类是否已经被父类加载器加载过,如果是,则直接返回父类加载器已经加载的Class对象,如果不是,则调用自定义类加载器的findClass方法来加载类。

重写findClass方法,自己实现查找类字节码文件的过程。在自定义类加载器的findClass方法中,可以使用Class.forName方法来加载类字节码文件,然后通过defineClass方法将字节码文件转换为Class对象。

需要注意的是,打破双亲委派机制可能会破坏Java虚拟机的安全机制,因此应该谨慎使用,避免产生潜在的安全隐患。同时,在使用自定义类加载器时,应该遵循类加载器的委派机制,尽可能地使用父类加载器加载类,只有在必要的情况下才使用自定义类加载器来加载类。