JAVA基础
java的第一个程序
JDK 、JRE、JVM 的区别
JDK包含了JRE,JRE包含了JVM。JVM(java virtual machine) JRE(java runtime environment) JDK(java development kit)
package 类似于文件夹,用于管理各种class。包名的命名是域名倒着写,类似于com.baidu。
API(application programming interface)应用程序接口。API的作用类似于字典。在API中查找各种包中包含的类的使用说明
1 | package com.guigu.java; |
主函数main在public class 函数里面。一个package里面只能有一个public 类。主函数是一个程序的入口。
java的输入与输出
- 输出
1 | System.out.println(" ");//输出换行 |
- 输入
1 | import java.util.Scanner; |
java的各种类型的数据
整数类型
==Integer.toBinaryString(a)==把a转为二进制表示形式
==Integer.toOctalString(a)==把a转为8进制形式
==Integer.toHexString(a)==把a转为16进制
- byte
占用一个字节(8位)表示范围 -128——127。
- short
占用2个字节(16位)大约正负3*104多。
- int
占用4个字节, (2^31)-1。大约正负21亿。
- long
占用8个字节。 263-1
浮点数:
浮点数默认为double类型,要将其变为float类型,需要在数字后面加F/f
科学计数法 列如3.12e2 表示3.12*102。
布尔类型
- 1代表真,0 代表假
字符型
char a='sf',注意使用的是单引号,String类型才使用双引号
字符可以直接转化为数字,是使用ASC Ⅱ 转化的
可以使用强制转型把数字转化为字符型(char)a;
类型转换的规则
- 容量小的数据类型可以自动转换为容量大的数据类型
1 | int i=3;//编译不会报错 |
- 可以将整型变量直接赋值给byte,short,char 只要不超出其范围
1 | char a=2; |
- 强制转换
强制转换是让不能自动转换的数字强制转换为我们想要的类型。使用方法:
1 | double a=2.3;//把a强制转换为float类型。 |
面向对象编程
概念
==类==是面向对象编程语言的一个重要概念,它是对一项事物的抽象概括,可以包含该事物的一些属性定义,以及操作属性的方法。 ==实例==就是创建这个类对应的实际对象。类只是对事物的描述,而实例化就是相当于为这个描述开辟了一块内存。 ==变量(属性)==分为: 成员变量: 1、成员变量定义在类中,在整个类中都可以被访问。
2、成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。
3、成员变量有默认初始化值。 类变量(静态变量): 由static关键字修饰的变量称为静态变量,其实质上就是一个全局变量。如果某个内容是被所有对象所共享,那么该内容就应该用静态修饰
成员变量和类变量的区别: 1、两个变量的生命周期不同
成员变量随着对象的创建而存在,随着对象的回收而释放。
静态变量随着类的加载而存在,随着类的消失而消失。
2、调用方式不同
成员变量只能被对象调用。
静态变量可以被对象调用,还可以被类名调用。
3、别名不同
成员变量也称为实例变量。
静态变量也称为类变量。
4、数据存储位置不同
成员变量存储在==堆内存==的对象中,所以也叫对象的特有数据。
静态变量数据存储在方法区(共享数据区)的==静态区==,所以也叫对象的共享数据。
1 | //一个简单的例子 |
继承
面向对象的三个基本特征之一(另外两个是多态和封装)。 ==继承==就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。 子类的创建可以增加新数据、新功能,可以继承父类全部的功能,但是不能选择性的继承父类的部分功能。继承是==类与类之间==的关系,不是对象与对象之间的关系。 作用:
- 继承的出现提高了代码的复用性。
- 继承的出现让类与类之间产生了关系,提供了多态的前提。
- 不要仅为了获取其他类中某个功能而去继承
关于继承的规则:
- 子类不能直接访问父类中私有的(private)的成员变量和方法。
方法的重写(override)
定义:在子类中可以根据需要对从父类中继承来的方法进行改造,也称方法的重置、覆盖。在程序执行时,子类的方法将覆盖父类的方法。
要求:
- 重写方法必须和被重写方法具有相同的方法名称、参数列表和返回值类型。
- 重写方法不能使用比被重写方法更严格的访问权限。
- 重写和被重写的方法须同时为static的,或同时为非static的
- 子类方法抛出的异常不能大于父类被重写方法的异常


###继承实现
java 中,使用关键字==extends==来体现子类继承父类。
1 | class Animal { |
多态
多态是建立在重写(override)和继承(extends)上的 三个必要条件:要有继承,要有方法重写,父类引用指向子类引用 主要的使用是在父类之下还有多个子类,然后,在其他的函数定义,需要使用这个类以及它的子类的时候,我们可以模糊化。用父类去代表整个子类。在使用这个函数的时候,再明确指出使用哪一个
1 | public class ani_mal { |
抽象类
在父类里面定义一个抽象方法,在不同的子类里面分别重写这个方法。关键字是abstract-
- abstract class 抽象类
- abstract void run() 抽象方法
有抽象方法的类只能定义为抽象类。抽象类里也可以有普通的方法。
- 抽象类不能实体化,即抽象类没有对象
- 抽象类只能用来继承
- 抽象方法必须被子类实现
1 | public abstract class An_imal { |
interface
接口:接口只定义各种方法,之后的继承它的类必须要把那些方法实现。类似于继承,它使用的关键字是implements
- 有时必须从几个类中派生出一个子类,继承它们所有的属性和方法。但是,Java不支持多重继承。有了接口,就可以得到多重继承的效果。
- 接口(interface)是抽象方法和常量值的定义的集合。
- 从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有变量和方法的实现。
- 实现接口类:class SubClass implements InterfaceA{ }一个类可以实现多个接口,接口也可以继承其它接口。

1 | public interface Interface { |
封装
概念
面向对象特征之一:封装和隐藏 :使用者对类内部定义的属性(对象的成员变量)的直接操作会导致数据的错误、混乱或安全性问题。
1 | class Animal { |
应该将legs属性保护起来,防止乱用。保护的方式:信息隐藏
Java中通过将数据声明为私有的(private),再提供公共的(public)方法:getXxx()和setXxx()实现对该属性的操作,以实现下述目的:
隐藏一个类中不需要对外提供的实现细节;
使用者只能通过事先定制好的方法来访问数据,可以方便地加入控制逻辑,限制对属性的不合理操作;
便于修改,增强代码的可维护性;
1 | public class Animal{ |
权限修饰符
Java权限修饰符public、protected、private置于类的成员定义前,用来限定对象对该类成员的访问权限。
修饰符 | 类内部 | 同一个包 | 子类 | 任何地方 |
---|---|---|---|---|
private | Yes | |||
(缺省) | Yes | Yes | ||
protected | Yes | Yes | Yes | |
public | Yes | Yes | Yes | Yes |
- 对于class的权限修饰只可以用public和default(缺省)。
- public类可以在任意地方被访问。
- default类只可以被同一个包内部的类访问。
构造器(构造方法)
- 构造器的特征它具有与类相同的名称
- 它不声明返回值类型。(与声明为void不同)
- 不能被static、final、synchronized、abstract、native修饰
- 不能有return语句返回值
构造器的作用:创建对象;给对象进行初始化
- 如:Order o = new Order(); Person p = new Person(Peter,15);
- 如同我们规定每个“人”一出生就必须先洗澡,我们就可以在“人”的构造方法中加入完成“洗澡”的程序代码,于是每个“人”一出生就会自动完成“洗澡”,程序就不必再在每个人刚出生时一个一个地告诉他们要“洗澡”了。
语法格式
1 | public class Animal { |
根据参数不同,构造器可以分为如下两类:
- 隐式无参构造器(系统默认提供)
- 显式定义一个或多个构造器(无参、有参)
注意:
- Java语言中,每个类都至少有一个构造器
- 默认构造器的修饰符与所属类的修饰符一致
- 一旦显式定义了构造器,则系统不再提供默认构造器
- 一个类可以创建多个重载的构造器
- 父类的构造器不可被子类继承
构造器重载
1 | public class Person { |
关键字—this
在java中,this关键字比较难理解,它的作用和其词义很接近。
- 它在方法内部使用,即这个方法所属对象的引用;
- 它在构造器内部使用,表示该构造器正在初始化的对象。
this表示当前对象,可以调用类的属性、方法和构造器
什么时候使用this关键字呢?
- 当在方法内需要用到调用该方法的对象时,就用this。
1 | class Person{ // 定义Person类 |
- 当形参与成员变量重名时,如果在方法内部需要使用成员变量,必须添加this来表明该变量时类成员
- 在任意方法内,如果使用当前类的成员变量或成员方法可以在其前面添加this,增强程序的阅读性
使用this调用本类的构造器
1 | class Person{ // 定义Person类 |
- 使用this()必须放在构造器的首行!
- 使用this调用本类中其他的构造器,保证至少有一个构造器是不用this的。
1 | class Person{ // 定义Person类 |
JavaBean
- JavaBean是一种Java语言写成的可重用组件。
- 所谓javaBean,是指符合如下标准的Java类:
- 类是公共的
- 有一个无参的公共的构造器有属性
- 有对应的get、set方法
- 用户可以使用JavaBean将功能、处理、值、数据库访问和其他任何可以用java代码创造的对象进行打包,并且其他的开发者可以通过内部的JSP页面、Servlet、其他JavaBean、applet程序或者应用来使用这些对象。用户可以认为JavaBean提供了一种随时随地的复制和粘贴的功能,而不用关心任何改变。
1 | public class TestJavaBean{ |
UML类
- +表示 public 类型, - 表示 private 类型,#表示protected类型
- 方法的写法: 方法的类型(+、-) 方法名(参数名: 参数类型):返回值类型
关键字—package
package语句作为Java源文件的第一条语句,指明该文件中定义的类所在的包。(若缺省该语句,则指定为无名包)。它的格式为: package 顶层包名.子包名 ;
1 | //举例:pack\Test.java |
- 包对应于文件系统的目录,package语句中,用 “.” 来指明包(目录)的层次;
- 包通常用小写单词,类名首字母通常大写。
关键字—import
为使用定义在不同包中的Java类,需用import语句来引入指定包层次下所需要的类或全部类(.*)。
import语句告诉编译器到哪里去寻找类。
语法格式:import 包名[.子包名…]. <类名 |*>
1 | import p1.Test; //import p1.*;表示引入p1包中的所有类 |
- 若引入的包为:java.lang,则编译器默认可获取此包下的类,不需要再显示声明。
- import语句出现在package语句之后、类定义之前
- 一个源文件中可包含多个import语句
- 可以使用import lee.* ;语句,表明导入lee包下的所有类。而lee包下sub子包内的类则不会被导入。import lee.sub.*;
- import语句不是必需的,可坚持在类里使用其它类的全名
- JDK 1.5加入import static语句
JDK中主要的包介绍
- java.lang—-包含一些Java语言的核心类,如String、Math、Integer、 System和Thread,提供常用功能
- java.net—-包含执行与网络相关的操作的类和接口。
- java.io —-包含能提供多种输入/输出功能的类。
- java.util—-包含一些实用工具类,如定义系统特性、接口的集合框架类、使用与日期日历相关的函数。
- java.text—-包含了一些java格式化相关的类
- java.sql—-包含了java进行JDBC数据库编程的相关类/接口
- java.awt—-包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)。
- java.applet—-包含applet运行所需的一些类。
Object类
- Object类是所有Java类的根父类
- 如果在类的声明中未使用extends关键字指明其父类,则默认父类为Object类
1 | method(Object obj){…}//可以接收任何类作为其参数 |
Object类中的主要方法
方法名称 | 类型 | 描述 |
---|---|---|
public Object() | 构造 | 构造方法 |
public boolean equals(Object obj) | 普通 | 对象比较 |
public int hashCode() | 普通 | 取得Hash码 |
public String toString() | 普通 | 对象打印时调用 |
equals方法
==操作符:
基本类型比较值:只要两个变量的值相等,即为true.
int a=5; if(a==6){…}
引用类型比较引用(是否指向同一个对象):只有指向同一个对象时,==才返回true.
Person p1=new Person(); Person p2=new Person(); if (p1==p2){…}
“==”进行比较时,符号两边的数据类型必须兼容(可自动转换的基本数据类型除外),否则编译出错;
equals():
所有类都继承了Object,也就获得了equals()方法。还可以重写。
只能比较引用类型,其作用与“==”相同,比较是否指向同一个对象。格式:obj1.equals(obj2)
特例
:当用equals()方法进行比较时,对类File、String、Date及包装类(Wrapper Class)来说,是
比较类型及内容
而不考虑引用的是否是同一个对象;
- 原因:在这些类中重写了Object类的equals()方法。
可重写equals方法更改两个引用数据类型相等的条件
toString()方法
- toString()方法在Object类中定义,其返回值是String类型,返回类名和它的引用地址。在
- 进行String与其它类型数据的连接操作时,自动调用toString()方法
Date now=new Date();
System.out.println(“now=”+now)
; 相当于System.out.println(“now=”+now.toString());
可以根据需要在用户自定义类型中重写toString()方法 如String类重写了toString()方法,返回字符串的值。s1=“hello”; System.out.println(s1);//相当于System.out.println(s1.toString()); - 基本类型数据转换为String类型时,调用了对应包装类的toString()方法int a=10; System.out.println(“a=”+a);
包装类(Wrapper)
- 针对八种基本定义相应的引用类型—包装类(封装类)
- 有了类的特点,就可以调用类中的方法。
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
byte | Byte |
short | Short |
int | Integer |
long | Long |
char | Character |
float | Float |
double | Double |
装箱
基本数据类型包装成包装类的实例
- 通过包装类的构造器实现:
- int i = 500;
- Integer t = new Integer(i);
- 还可以通过字符串参数构造包装类对象:
- Float f = new Float(“4.56”);
- Long l = new Long(“asdf”);
- //NumberFormatException
拆箱
获得包装类对象中包装的基本类型变量
- 调用包装类的.xxxValue()方法:
- boolean b = bObj.booleanValue();
- JDK1.5之后,支持自动装箱,自动拆箱。但类型必须匹配。
字符串与基本数据类型转换
字符串转换成基本数据类型
- 通过包装类的构造器实现:
- int i = new Integer(“12”);
- 通过包装类的parseXxx(String s)静态方法:
- Float f = Float.parseFloat(“12.1”);
基本数据类型转换成字符串
- 调用字符串重载的valueOf()方法:
- String fstr = String.valueOf(2.34f);
- 更直接的方式:
- String intStr = 5 + “”
包装类在实际开发中用的最多的在于字符串变为基本数据类型。
异常处理
概述
在使用计算机语言进行项目开发的过程中,即使程序员把代码写得尽善尽美,在系统的运行过程中仍然会遇到一些问题,因为很多问题不是靠代码能够避免的,比如:客户输入数据的格式,读取文件是否存在,网络是否始终保持通畅等等。
异常:在Java语言中,将程序执行中发生的不正常情况称为“异常”。(开发过程中的语法错误和逻辑错误不是异常)
Java程序在执行过程中所发生的异常事件可分为两类:
- Error
Java虚拟机无法解决的严重问题。
- 如:JVM系统内部错误、资源耗尽等严重情况。
一般不编写针对性的代码进行处理。
- Exception
其它因编程错误或偶然的外在因素导致的一般性问题,可以使用针对性的代码进行处理。例如:
- 空指针访问
- 试图读取不存在的文件
- 网络连接中断
解决方法:
- 一是遇到错误就终止程序的运行。
- 另一种方法是由程序员在编写程序时,就考虑到错误的检测、错误消息的提示,以及错误的处理。
捕获错误最理想的是在编译期间,但有的错误只有在运行时才会发生。比如:除数为0,数组下标越界等
分类:
编译时异常
- 是指编译器不要求强制处置的异常。一般是指编程时的逻辑错误,是程序员应该积极避免其出现的异常。
- java.lang.RuntimeException类及它的子类都是运行时异常。
- 对于这类异常,可以不作处理,因为这类异常很普遍,若全处理可能会对程序的可读性和运行效率产生影响。
运行时异常
- 是指编译器要求必须处置的异常。即程序在运行时由于外界因素造成的一般性异常。编译器要求java程序必须捕获或声明所有编译时异常。
- 对于这类异常,如果程序不处理,可能会带来意想不到的结果。
Java异常类层次
常见异常
- java.lang.RuntimeException
- ClassCastException
- ArrayIndexOutOfBoundsException
- NullPointerException
- ArithmeticException
- java.io.IOExeption
- FileNotFoundException
- EOFException
- java.lang.ClassNotFoundException
- java.lang.InterruptedException
- java.io.FileNotFoundException
- java.sql.SQLException
异常举例
1 | public class Test6_1{ |
1 | public class NullRef{ |
1 | public class DivideZero{ |
1 | class Person { |
异常处理
在编写程序时,经常要在可能出现错误的地方加上检测的代码,如进行x/y运算时,要检测分母为0,数据为空,输入的不是数据而是字符等。过多的分支会导致程序的代码加长,可读性差。因此采用异常机制。
Java异常处理采用异常处理机制,将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁,并易于维护。
- Java提供的是异常处理的抓抛模型。
- Java程序的执行过程中如出现异常,会生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
- 异常对象的生成
- 由虚拟机自动生成:程序运行过程中,虚拟机检测到程序发生了问题,如果在当前代码中没有找到相应的处理程序,就会在后台自动创建一个对应异常类的实例对象并抛出——自动抛出
- 由开发人员手动创建:Exception exception = new ClassCastException();——创建好的异常对象不抛出对程序没有任何影响,和创建一个普通对象一样
- 如果一个方法内抛出异常,该异常对象会被抛给调用者方法中处理。如果异常没有在调用者方法中处理,它继续被抛给这个调用方法的上层方法。这个过程将一直继续下去,直到异常被处理。这一过程称为捕获(catch)异常。
- 如果一个异常回到main()方法,并且main()也不处理,则程序运行终止。程序员通常只能处理Exception,而对Error无能为力。
异常处理是通过try-catch-finally语句实现的
1 | try{ |
try
捕获异常的第一步是用try{…}语句块选定捕获异常的范围,将可能出现异常的代码放在try语句块中。
catch (Exceptiontype e)
在catch语句块中是对异常对象进行处理的代码。每个try语句块可以伴随一个或多个catch语句,用于处理可能产生的不同类型的异常对象。
如果明确知道产生的是何种异常,可以用该异常类作为catch的参数;也可以用其父类作为catch的参数。
比如:可以用ArithmeticException类作为参数的地方,就可以用RuntimeException类作为参数,或者用所有异常的父类Exception类作为参数。但不能是与ArithmeticException类无关的异常,如NullPointerException(catch中的语句将不会执行)。
捕获异常的有关信息:
与其它对象一样,可以访问一个异常对象的成员变量或调用它的方法。
- getMessage() 获取异常信息,返回字符串
- printStackTrace() 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
finally
- 捕获异常的最后一步是通过finally语句为异常处理提供一个统一的出口,使得在控制流转到程序的其它部分以前,能够对程序的状态作统一的管理。
- 不论在try代码块中是否发生了异常事件,catch语句是否执行,catch语句是否有异常,catch语句中是否有return,finally块中的语句都会被执行。
- finally语句和catch语句是任选的
异常处理举例
1 | public class Test6_2{ |
1 | public class DivideZero1{ |
声明抛出异常
声明抛出异常是Java中处理异常的第二种方式
- 如果一个方法(中的语句执行时)可能生成某种异常,但是并不能确定如何处理这种异常,则此方法应显示地声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理。
- 在方法声明中用throws语句可以声明抛出异常的列表,throws后面的异常类型可以是方法中产生的异常类型,也可以是它的父类。
- 重写方法不能抛出比被重写方法范围更大的异常类型。在多态的情况下,对methodA()方法的调用-异常的捕获按父类声明的异常处理。
1 | class A { |
人工抛出异常
Java异常类对象除在程序执行过程中出现异常时由系统自动生成并抛出,也可根据需要人工创建并抛出。
- 首先要生成异常类对象,然后通过throw语句实现抛出操作(提交给Java运行环境)。
IOException e = new IOException();throw e;
- 可以抛出的异常必须是Throwable或其子类的实例。下面的语句在编译时将会产生语法错误:
throw new String("want to throw");
自定义异常类
- 一般地,用户自定义异常类都是RuntimeException的子类。
- 自定义异常类通常需要编写几个重载的构造器。
- 自定义的异常类对象通过throw抛出。
- 自定义异常最重要的是异常类的名字,当异常出现时,可以根据名字判断异常类型。
- 用户自己的异常类必须继承现有的异常类。
创建
1 | class MyException extends Exception { |
使用
1 | public class Test6_5{ |

反射
反射:被视为动态语言的关键。它允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
好处
- 可以在程序的运行过程中操作这些对象。
- 可以解耦,提高程序的可拓展性
获取class类对象的方式
1、Class.forName("全类名"):将字节码文件加载进内存,返回Class对象 多用于配置文件,将类名定义在配置文件中,读取文件,加载类
2、类名.Class:通过类名的属性Class获取 多用于参数的传递
3、对象.getclass():getclass()方法在Object类中定义。
这三种方法分别对应了Java代码在计算机中经历的三个阶段。
类加载器把java代码加载为了Class类对象时,成员变量、构造方法、成员方法都被抽取出来,封装为对象了。所有的成员变量对象都放在了一个叫做Filed[] 的数组里。其他同理。
不管通过那种方式,获取到的Class对象是同一个。 因为同一个字节码文件(*.class)在程序运行的过程中,只会被加载一次。
Class对象的功能
获取功能 1、获取成员变量们
Filed[] getFileds() 获取所有public修饰的成员变量
1
2
3
4
5
6Class PersonClass = Person.class;
Filed[] getFileds() 获取所有public修饰的成员变量
Field[] fields= PersonClass.getFields();
for (Field field:fields){
System.out.println(field);
}Filed getFiled(String name) 获取某个成员变量
1
2
3
4
5
6
7
8
9
10
11
12
13/ 得到成员变量之后有啥用:可以获取成员变量的值和设置成员变量的值
// get() & set()
Field a = PersonClass.getField("a");
Person p1 =new Person();
// 获取值
Object value = a.get(p1);
System.out.println(value);
// 设置值
a.set(p1,15);
System.out.println(p1.a);Filed[] getDeclaredFields() 获取所有的成员变量。意味着私有的成员变量也能获取。
1
2
3
4// declared 方法
Field[] fields = PersonClass.getDeclaredFields();
for (Field field:fields){
System.out.println(field);Filed getDeclaredField(String name)
1
2
3
4
5
6// 获取单个的declared对象
Field nameField = PersonClass.getDeclaredField("name");
// 这里,使用私有的成员变量时需要忽略访问权限修饰符额安全检查
nameField.setAccessible(true);
nameField.set(p1,"小黄");
System.out.println ((String)nameField.get(p1));
2、获取构造方法们 作用:获取到构造方法后,可以创建对应的对象。
Constructor<?>[] getConstructors()
Constuctor
getConstructor(类<?>... parameterTypes) 1
2
3Class classPerson = Person.class;
Constructor constructor = classPerson.getConstructor(String.class,int.class,int.class,String.class);
Person person =(Person) constructor.newInstance("aaa",123,122,"小小");Constructor
getDeclaredConstructor(类<?>... ParameterTypes) Constructor<?>[] getDeclaredConstructors()
3、获取成员方法们
Method[] getMethods()
Method getMethod(String name ,类<?>... paraterTpyes)
1
2
3
4
5Class personClass = Person.class;
Method method = personClass.getMethod("setB", String.class);
Person p1= new Person();
method.invoke(p1,"起飞");
System.out.println(p1.getB());Method[] getDeclareMethods()
Method getDeclareMethod(String name ,类<?>... paraterTpyes)
4、获取类名
- String getName()
注解
概念:说明程序的,是给计算机看的。
作用分类:
- 编写文档:通过代码里标识的注解生成doc文档
- 代码分析;通过代码标识的注解对代码进行分析(使用反射)
- 编译检查:通过代码里标识的注解让编译器能够实现基本的编译检查
JDK 中预置的一些注解
1、@override 检测被该注解标注的方式是否是继承自父类(接口)
2、@Deprecated 该注解标注的内容,已经过时
3、@SuppressWarnings 压制警告。一般传入参数"all"
自定义注解
格式:public @interface 注解名称{}
本质:注解本质上是一个接口,该接口默认继承Annotation接口。
属性:接口中可以定义的成员方法。 要求:
属性的返回值类型 1、基本数据类型 2、String 3、枚举 4、注解 5、以上类型的数组
定义了属性,在使用时需要给属性赋值
元注解
用于描述注解的注解 1、@Target 描述注解能够作用的位置 2、@Retention 描述注解被保留的阶段 3、@Documented 描述注解是否被抽取到api文档中 4、@Inherited 描述注解是否被子类继承
解析、使用注解
- 1、获取有注解类的字节码文件对象
Clss xxx = xxx.class
- 2、获取字节码文件对象里的注解对象
XX name = xxx.getAnnotation(XX.class)
.//在内存中生成了 一个该注解接口的子类实现对象。 - 3、调用注解对象中定义的抽象方法,获取返回值
Strng、int... xxxx = name.方法()
JVM核心
类加载机制:JVM把class文件加载到内存,并对数据进行校验、解析和初始化,最终形成JVM可以直接使用的Java类型的过程
加载
将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区中的运行时二进制的数据结构。在堆中生成一个代表整个类的java.lang.Class对象,作为方法区类数据的访问入口。这个类就是反射中我们得到的那个Class类
链接
将Java类的二进制代码合并到JVM的运行状态之中的过程。
- 验证;确保加载的类的信息符合JVM规范,没有安全方面的问题
- 准备:正式为类变量即static变量分配内存并设置类变量初始值的阶段。这些内存都将在方法区进行分配
- 解析:虚拟机常量池内的符号引用替换为直接引用的过程
初始化
初始化阶段是执行类构造器
当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化
虚拟机会保证一个类的
当访问一个Java类的静态域时,只有真正声明这个域的类才会被初始化。
方法区获取到每个class 的运行时数据,同时也进行静态变量和方法的初始化。之后才产生一个与之对应的在堆中的代表这整个类的java.lang.Class对象。之后才执行代码。main方法执行时,会在栈中生成一个栈帧(每个方法执行时,都会生成一个自己的栈帧)。
类的引用
什么时候会发生类的初始化:
- new一个类的对象
- 使用类的静态成员
- 使用java.lang.reflect包的方法对类进行反射调用
- 当初始化一个类,如果父类没有初始化,则会先初始化它的父类
类的被动引用(不会发生类的初始化)
- 引用final的常量时,不会发生初始化
- 访问静态域时,只有真正声明这个域的类才会初始化。例如:B extends A,A中声明了一个static int width。在main方法中,使用B.width,但是初始化的类是A
类加载器
类加载器的层次结构
- 引导类加载器:它用来加载Java 的核心库(JAVA_HOME/jre/lib/rt.jar),是用原生代码(c++)来实现的,并不继承自java.lang.Classloader
以下的类都继承自java.lang.ClassLoader
- 扩展类加载器:用来加载(JAVA_HOME/jre/ext/*.jar)
- 应用程序类加载器(application class loader)
- 自定义类加载器(User Defined ClassLoader)
java.lang.ClassLoader类的基本职责:根据一个指定的类的名称,找到或者生成对应的字节码文件,然后从这些字节码代码中定义出一个java类,即java.lang.Class类的实例。除此之外,ClassLoader还负责加载java应用所需要的资源,如图像,文件和配置文件等