包:
1、包的作用:
(1)避免类的同名(区分类);类的全名称:包.类名
回忆:java.util.Scanner
java.util.Arrays
java.lang.String
j
(2)可以限定某些类或成员的可见范围;(权限)
如果某个类或成员省略了权限修饰符,它的可见范围是本包
(3)用于组织管理项目中众多的类
2、包的声明的格式:package 包名;
声明的要求:
(1)这句package语句必须在“源文件”代码的首行
(2)包名:A:所有单词都小写,每一个单词之间使用.分割; B:一般习惯上用公司的域名倒置加模块名 com.atguigu.xxx;
3、
编译:javac 源文件名.java; ----->>> 编译:javac -d . 源文件名.java
运行:java 类名 ----->>> 运行:java 包.类名
-d:directory文件夹,目录; .:表示当前目录
4、如何使用其他的包? 前提:被使用的类必须是可见的
(1)使用类的全名称
(2)使用import语句先导包,然后使用类的简名称; import 包.类名;
特殊情况:要使用的两个类同名,包名不一样;那就一个导包用简名称,一个使用全名称
* 导包:
* (1)import 包.类名;
* (2)import 包.*;
* (3)import static 包.类名.静态成员;
* (4)import static 包.类名.*;
*
* (3)(4)就是静态导入,JDK1.5之后引入
*
* JDK1.5增加的:
* (1)foreach
* (2)枚举
* (3)注解
* (4)可变参数
* (5)静态导入
* JDK1.8增加的:
* (1)接口的默认方法和静态方法
final关键字
* 关键字:final,最终的
* 它也是一个修饰符
*
* 1、它可以修饰什么?
* final可以修饰:类(包括外部类和内部类)、变量(包括局部变量、实例变量和类变量)、方法(静态方法和非静态方法); final不能用于修饰构造方法
*
* 2、它修饰后有什么不同?
* (1)修饰类,即class前面出现了final
* 表示这个类是最终类,即这个类不能被继承了,没有子类,它是太监类,没有子孙后代
* 例如:String类
*
* (2)修饰方法,即返回值类型前面出现final
* 表示这个方法是最终实现版本,即这个方法不能被重写
*
* (3)修饰变量,即在变量数据类型前面出现final; 被final修饰的变量只能在变量定义时初始化。
* 表示这个变量的值不能被修改,它是常量,一般要求常量名大写,每个单词之间使用_,常量必须赋值
*
* 例如:Math.PI
native关键字
* 关键字:native
* 它也是修饰符
*
* 1、native可以修饰什么?
* 可以修饰方法
*
* 2、native修饰的方法是什么意思?
* 表示这个方法是一个“原生”的方法,即它的方法体的实现不是用Java语言实现的,是有C/C++等语言实现的,
* 实现后编译为.dll文件,然后由Java代码调用。
*
* 对应调用者,使用者来说,可以把它当成Java实现的方法一样使用。
* 而且子类可以选择用Java代码重写native方法
*/
public class TestNative {
public static void main(String[] args) {
Object obj = new Object();
int hashCode = obj.hashCode();
System.out.println(hashCode);
}
}
class Student{
private int id;
private String name;
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
View Code
接口
* 1、声明一个接口
* 【修饰符】 interface 接口名{
} //类似于类的声明(class)
可以用来修饰interface的有public, static也对; private和protected都不对;接口的内部成员都是public
2、接口的成员 * JDK1.8之前: * (1)全局静态的常量 public static final 如 int MAX_SPEED = 20000; * (2)公共的抽象的方法 public abstract 如:void run(); * JDK1.8之后:增加了两个成员 * (1)默认方法 * (2)静态方法 * 3、如何使用接口? * (1)全局静态的常量:通过接口名直接调用 * (2)抽象方法,由实现类(就是子类)来实现它;;;“子类“要实现接口重写接口的方法,不一定要继承父类。 * * 【修饰符】 class 实现类名 implements 接口们{ * //如果这个类不是抽象类,那么必须实现接口的所有的抽象方法 * } * * 接口可以比喻成“干爹”,可以有好几个 * 继承可以比喻成“亲爹”,只能有一个,所以单继承 * * 4、接口的特点 * (1)接口也是不能直接创建对象 * (2)一个类可以同时实现多个接口 * (3)一个类可以同时继承它的父类,又实现接口,要求必须继承在前,实现在后 * 【修饰符】 class 实现类名 extends 父类 implements 接口们{ * //如果这个类不是抽象类,那么必须实现接口的所有的抽象方法 * } * (4)接口和父类有点像,所以接口的变量与实现类对象可以构成多态引用 * (5)一个实现类实现接口时,必须实现接口的所有的抽象方法,否则这个实现类也得是抽象类 * (6)接口可以继承接口,并且可以继承多个接口。 * 【修饰符】interface 接口名 extends 接口们{ * } * * 关系: * 类与类之间:继承,单继承 extends * 类与接口之间:类实现接口,可以多实现 implements * 接口与接口之间:继承,多继承 extends *
for(int i = 1; i < arr.length; i++){
for(int j = 0; j < arr.length - i; j++){
/*
* 假设传入的是Student[]数组,里面都是学生对象
* 如何表示前面的学生对象arr[j]比arr[j+1]大
*/
//需要调用arr[j]的compare方法,怎么才能调用compary方法呢,
//参数为Object类型向下转型为Student类型,它重写了compary方法
//通过arr[j].compare(arr[j+1])>0,就可以确定arr[j]比较arr[j+1]大
Sortable left = (Sortable) arr[j];//这一步很关键啊
if(left.compare(arr[j + 1]) > 0){ //if(arr[j] > arr[j+1]){
//交换两个元素,temp和元素的类型一样就可以
Object temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
}
* JDK1.8之后,接口增加了两个成员:
* 1、静态方法
* 和类中的静态方法的格式一样。
* 调用时:通过“接口名."调用即可
*
* 原来的核心类库中,有Collection接口和Collections工具类(全部是静态方法),
* Path接口和Paths工具类(全部是静态方法)
* 后面的工具类是为前面的接口服务的。
* 原来为了为某个接口提供工具类,还要增加一个类,现在就不同了,直接在接口中声明静态方法即可。
* 而且这些静态的实现和接口的实现类是什么类型无关。
*
* 2、默认方法
* 语法格式:
* 【修饰符】 interface 接口{
* 【修饰符】 default 返回值类型 方法名([形参列表]){
* 方法体
* }
* }
*
* 如何调用?
* 必须通过接口的"实现类对象."才能调用
*
* 某一个接口的某个抽象方法,可能它的多数实现类对该方法的实现是一样的,那么就没必要每一个实现类都写一遍。
* 把这样的方法实现,提取到接口中声明为默认方法,如果其他不一样的实现类,可以选择“重写”。
*/
public class TestInterface {
public static void main(String[] args) {
MyInter.test(); //接口中的静态方法直接 接口名.静态方法;
MyImp myimp = new MyImp();
myimp.fun();//通过接口的实现类对象来调用 接口的default默认方法;
myimp.method();//通过接口的实现类对象来调用 接口的default默认方法;
}
}
interface MyInter{
public static void test(){
System.out.println("接口中的静态方法直接接口名.来调用哦");
}
public default void fun(){
System.out.println("接口中的默认方法fun通过接口的实现类创建对象来调用");
}
public default void method(){
System.out.println("接口中默认方法method通过接口的实现类创建对象来调用");
}
}
class MyImp implements MyInter{
/*@Override //接口中的方法不是抽象方法,可以不用重写;
public void fun() {
// TODO Auto-generated method stub
MyInter.super.fun();
}
*/
}
View Code
/*
* 默认方法的冲突问题:
* 1、当某个类实现了多个接口,多个接口的默认方法的方法签名是一样的
* 必须重写,但是在重写的时候可以选择(1)保留其中一个(2)选择完全重写
*
* 2、当某个类继承了父类,又实现了接口,但是父类中有一个方法和接口中的默认方法的方法签名是一样的
* 默认选择保留“父类”,即子类创建对象默认调用的是父类中的方法,如果子类重写了父类的方法就按照子类重写的方法;
当然也可以重写接口中的方法,就会调用接口中的方法,如 InterD.super.test( ) ;
当然也可以选择重写(1)选择父接口的(2)完全重写
*/
public class TestDefaultMethod {
public static void main(String[] args) {
Sub s = new Sub();
s.test();
Son son = new Son();
son.test(); //如果子类没有重写,就默认调用父类的
}
}
interface InterA{
public default void test(){
System.out.println("我是接口A的默认方法test");
}
}
interface InterB{
public default void test(){
System.out.println("我是接口B的默认方法test");
}
}
class Father{
}
class Sub extends Father implements InterA, InterB{
@Override
public void test() {
// TODO Auto-generated method stub
InterA.super.test();//保留A接口的默认实现
InterB.super.test();//保留A接口的默认实现,也可以实现两个都保留;也可以进行重写;
System.out.println("我重写,两个都不要了");
}
}
interface InterD{
public default void test(){
System.out.println("我是接口D中的默认方法test");
}
}
class Fu{
public void test(){
System.out.println("我是父类Fu中的方法test");
}
}
class Son extends Fu implements InterD{
public void test(){
InterD.super.test(); //重写接口D中的方法; 子类重写父类的方法了,就不会调用父类的方法了调它自己的
System.out.println("我是子类Son中的方法test,重写了父类的了");
}
}
View Code
用实现类代替接口
public class TestInterface {
public static void main(String[] args) {
//AA aa = new BB(); //需要一个接口,给个实现类即可
AA aa = new CC(); //多态的传递
// AA aa = new BB(); BB bb = new CC(); 构建CC,等同于构建他的父类,父类可以代替接口实现;能代替不代表实现了接口,class CC extends BB implements AA这样子就实现了接口
//System.out.println(aa);
System.out.println(CC.class.getInterfaces().length); //CC并没有实现接口AA
}
}
interface AA{
}
class BB implements AA{
}
class CC extends BB{
}
简单工厂模式
* 简单工厂模式(了解):
* (1)当创建某个对象比较麻烦
* (2)想要与被创建的对象的类型解耦合
*
* 工厂模式的目的:对象的创建者与对象的使用者角色分离
*
* 代码的结构:
* (1)接口
* (2)有接口的很多实现类
* (3)有一个工厂类,专门new接口的各种实现类的对象
* (4)使用接口的实现类对象的地方,通过工厂类之间获取对象,而不直接new实现类对象
*
* 耦合:依赖,关联
*/
public class TestFactory {
public static void main(String[] args) {
String str = new String(); //TestFactory与String类发生耦合,依赖
//对象的使用者TestFactory
//想要获取宝马车的对象; new出BMW对象,接口类型Car b
Car c = new BMW();//与BMW发生耦合,对象的使用者和创建者都是TestFactory
c.run();
//对象的使用者TestFactory不负责BMW和Aodi对象的创建,与BMW和Aodi类解耦合
Car b = Factory.getCar("宝马");
b.run();
Car a = Factory.getCar("奥迪");
a.run();
}
}
class Father{
}
class Son extends Father{
}
interface Car{
void run();
}
class BMW implements Car{
@Override
public void run() {
System.out.println("宝马来了。。。");
}
}
class AoDi implements Car{
@Override
public void run() {
System.out.println("奥迪来了。。。");
}
}
class Factory{
//工厂只负责创建对象;创建一个getCar方法来生产Car的对象
public static Car getCar(String type){
if("宝马".equals(type)){
return new BMW();
}else if("奥迪".equals(type)){
return new AoDi();
}
return null;
}
}
View Code
代理模式
* 代理:代购、中介
* 把麻烦,多变交给代理,核心的不易变化的还是自己来做。
*
* 静态代理和动态代理。
*
* 代理模式:(了解)
* 1、接口:主题接口
* 2、被代理者
* 3、代理者
* (1)被代理者和代理者都要实现主题接口。
* (2)要指定代理者为谁代理,即代理者中必须持有被代理者对象的引用
*
* 静态代理:
public class TestProxy {
public static void main(String[] args) {
DaiGou d = new DaiGou(new Customer()); //用有参构造器,创建DaiGou的对象d,并给他赋值初始化
d.buy(); //构造器中的形参Subject target, 把实参new出Customer对象传给它;最后由d对象来调用方法
}
}
interface Subject{
void buy(); //抽象方法省略了public abstract
}
//被代理者 --Customer类实现了Subject接口;
class Customer implements Subject{
@Override
public void buy() {
// 最核心的自己写
System.out.println("一手交钱一首交货");
}
}
class DaiGou implements Subject{
private Subject target; //类DaiGou的属性,接口类型的引用数据类型targer; 被代理者对象的引用
public DaiGou(Subject target) {
super();
this.target = target; //在构造器中给属性targer初始化
}
@Override
public void buy() {
System.out.println("筛选商品");
target.buy(); //一手交钱一首交货
System.out.println("反馈下");
}
}
View Code
枚举
* 枚举:也是一个种类型,也是一个类
* 1、什么是枚举?
* 中文:枚举 的近义词 列举,穷举,罗列
* Java中,枚举,罗列出该类型的所有对象
*
* 2、什么情况会用枚举?
* 当某个类型它的对象是有限的几个,这个时候就可以使用枚举。
* 3、如何声明枚举类
* JDK1.5之前
* JDK1.5之后
public class TestEnum {
public static void main(String[] args) {
// Season s = new Season();//构造器不可见
//如何获取春天对象
Season spring = Season.SPRING; 类型 类名 = 类型.静态对象
System.out.println(spring);
Season summer = Season.SUMMER;
System.out.println(summer);
}
}
//JDK1.5之前
/*
* (1)限定使用者创建对象; 2)把有限的几个对象,提前创建好,并存起来,大家共享
* 存对象:肯定用变量才能存; 共享:类变量,静态变量; 随处可用:public
*/
class Season{
//(2)把有限的几个对象,提前创建好,并存起来,大家共享
public static final Season SPRING = new Season();
public static final Season SUMMER = new Season();
public static final Season FALL = new Season();
public static final Season WINTER = new Season();
//(1)限定使用者创建对象,把构造器私有化
private Season(){
}
//可以定义其他的成员
public String toString(){
if(this == SPRING){
return "春眠不觉晓,处处闻啼鸟。";
}else if(this == SUMMER){
return "小荷才露尖尖角,早有蜻蜓立上头";
}else if(this == FALL){
return "停车坐爱枫林晚,霜叶红于二月花。";
}else{
return "千山鸟飞绝,万径人踪灭。";
}
}
}
* JDK1.5之后:
* 1、枚举类的声明格式
* 【修饰符】 enum 枚举类名{
* 枚举类的常量对象列表 【;
* 其他成员列表
* 】
* }
*
* 说明:
* (1)如果枚举常量对象列表后面要写其他成员,那么需要在常量对象列表后面加;分隔,如果没有其他成员,那么;可写可不写
* (2)构造器一定是私有化的
* (3)枚举类型的默认父类不是Object,而是java.lang.Enum类,当然Enum也是Object的子类
* 枚举类型不能再继承别的类型
*
* java.lang.Enum类:
* (1)构造器
* protected Enum(String name,int ordinal)
* name是为Enum类中的name属性赋值,自动赋值为常量对象的名称
* ordinal是Enum类中的ordinal属性赋值,自动赋值为常量对象的“序号”,这个序号是从0开始
*
* 他们的get方法没有按照普通类的get方法的命名,而是直接用属性名作为get方法的名称:name(),ordinal()
*
* 因为父类Enum只有唯一的一个有参构造,意味着我们自己写的枚举类的构造器和普通类(默认调用父类的无参构造)不一样,
* 默认调用的是父类的有参构造。
*
* (2)Enum实现了java.lang.Comparable接口
* 所有的枚举类型都支持比较大小,因为Enum实现了java.lang.Comparable接口,按照常量对象的顺序比较大小。
* 父类中把这个int compareTo()加了final,子类不能重写
*
* (3)两个API中没有的方法
* static 枚举类型[] values():用来返回枚举类型的所有常量对象
* static 枚举类型 valueOf(字符串类型的常量对象名) -->> 枚举类名.valueof(“ ”)
Week sunday = Week.SUNDAY;
System.out.println(sunday); //对象sunday打印的是 toString的内容;
System.out.println(sunday.name());
System.out.println(sunday.ordinal());
System.out.println("----------------");
Week[] values = Week.values();
for (Week week : values) {
System.out.println(week);
}
Week w = Week.valueOf("MONDAY");
System.out.println(w);
System.out.println(Week.valueOf("SUNDAY")); --->> 星期天 //(SUNDAY("星期天"); )
public enum Status {
BUSY("忙得热火朝天,无法再安排其他任务"), //创建的对象时候用的是有参构造;
FREE(), //用的是无参,默认null
VOCATION(),
LEFT("离职了");
private String desc;
private Status() {
}
private Status(String desc) {
this.desc = desc;
}
Status busy = Status.BUSY;
Employee[] emp = new Employee[5];
emp[0] = new Employee("kris", 10000, Status.BUSY);//busy
for (Employee employee : emp) {
System.out.println(employee.toString());//employee <==> employee.toString();
}
注释
注解(annotation):它又称为注释,它本质上也是注释,只不过它是代码级别的注释,即它用代码注释代码。
* 因为说注释容易让人误解为单行和多行的普通注释,很多人就故意叫做“注解”
* 注解是JDK1.5之后引入。
*
* 普通的注释:用文字去注释代码
* (1)单行注释
* (2)多行注释
*
* 文档注释:用代码和文字一起去注释代码。
*
* 注解长什么样? @注解
* 一个完整的注解,它应该有三部分组成:
* (1)定义,声明
* 可能是程序员自己声明的,也可能是别人声明好的;* 开发中,绝大多数都是用别人声明好的。
* (2)注解的使用
* 你看到在类上面、方法上面、属性上面....用到了@注解,就是在使用注解
* (3)读取注解
* 得有代码去读取这个注解,理解代码的用意,信息...
* 读取注解需要用代码去读取,这个代码我们称为“注解处理流程”,大多数情况下,这个代码也是别人写好的,
* 一般都是谁定义,谁复制编写读取注解的代码。
*
* 注解在后面的框架中使用最多,它的作用是用来替代xml的配置文件,对代码进行解释。
* 因为xml的配置方式,一个是复杂,另一个与所解释的代码是独立的,所以有的地方不用xml,用注解
常见的注解
* 常见的注解:
*
* 一、系统定义的最基本的三个注解(必须都认识,会写,会用)
* 1、@Override:
* 这个注解的声明是在JDK的核心类库中声明的,
* 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
* 这个注解的使用由程序员来使用,用在所有的重写的方法的上面,表示让编译器,按照重写的要求对该方法进行格式检查和编译。
*
* 重写的要求:
* (1)方法名和形参列表必须相同
* (2)返回值类型
* 如果是基本数据类型和void,必须相同
* 如果是引用数据类型,必须<= 子类重写的方法的返回值类型<=父类被重写的方法的返回值类型
* (3)权限修饰符:必须>= 子类重写的方法的权限修饰符的可见范围>=父类被重写的方法的权限修饰符的可见范围
* (4)抛出的异常列表类型范围:?
* (5)其他修饰符:被重写的方法不能是static,private,final
*
* 2、@SuppressWarings(xx)
* 这个注解的声明是在JDK的核心类库中声明的,
* 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
* 这个注解的使用由程序员来使用,用在任意需要抑制警告的地方
*
* @SuppressWarnings("all")
* @SuppressWarnings({ "rawtypes", "unused" })
*
* 3、@Deprecated
* 这个注解的声明是在JDK的核心类库中声明的,
* 这个注解的读取是编译器来读取的,编译器:javac.exe,eclipse中有自己编译器
* 这个注解的使用由程序员来使用,用在任意需要标记为“已过时”的元素上面,可能是方法,可能是类,
* “已过时”的东西,不建议程序继续使用的,如果使用可能有问题
*
* 删除的行为一定要谨慎。
*
* 编译器如果遇到了程序员使用了已标记为“已过时”的元素时,它会弹出警告
文档注解,文档注释
二、文档注解,文档注释
* 文档注解的声明,也有JDK核心类库声明过了; * 读取:javadoc.exe来读取
* @author:表示作者
* @version:表示版本
* @since:起始版本
* @see:另请参考
* @param:形参
* @return:返回值
* @throws:抛出的异常列表
*
* @param、@return、@throws只能在方法上使用
* @param 形参名 形参的数据类型 形参的解释
* @return 返回值类型 说明
* @throws 异常类型 说明
import javax.management.RuntimeErrorException;
/**
* @author Administrator
* @version 1.8
* @since 1.0
* @see java.lang.Object
* @see java.lang.Math
*/
public class TestAnnotation {
public static void main(String[] args) {
/**java程序主入口
* @param args String[] 命令行参数
*/
@SuppressWarnings(value = { "unused" })
int a = 10;
}
public static int getMax(int a, int b){
/**
* 从两个整数中找出最大值
* @param a int
* @param b int
* @return int 返回最大值
*/
return a > b ? a :b;
}
public static int divide(int a, int b) throws RuntimeErrorException{
/**
* 这是一个求两个整数的商
* @param int a
* @param int b
* @return int
* @throws RuntimeException,当b为0时抛出异常
*/
if(b == 0){
throw new RuntimeException("除数不能为0");
}
return a/b;
}
@Deprecated
public void print(){
System.out.println("过时的方法啊");
}
@Override
public String toString() {
return "TestAnnotation [toString()=" + super.toString() + "]";
}
}
View Code
单元测试
* JUnit框架不是JRE核心类库,需要单独引入它的jar,类库; eclipse等IDE(集成开发工具)都直接集成了JUnit框架
*
* 三、单元测试
* 声明和定义:JUnit框架中定义的* 读取:由java + JUnit框架读取
*
* 如何运行?
* 如果没有选择,那么当前源文件中的所有的单元测试都会运行
* 如果选中某个方法,只运行某一个;
*
* @Test: 要先引入import org.junit.Test;
*加在需要单独测试的方法。*
* @Before 导入 import org.junit.Before; 与之类似的 --->>> @After 是在@Test方法后边最后才执行。
* 加在需要在单元测试方法前面运行的方法上; 如public void test(){ }; *执行的特点:每一个@Test方法前面都会执行这个方法,再执行@Before;
*
* @BeforeClass @BeforeClass
* 加在需要在类初始化时执行的方法上。 如public static void test(){ }; 最先执行,首行位置;*
* @AfterClass 类似上边@BeforeClass的用法
* 加在需要在类所有的测试方法之后执行的方法上
*
这四个都有要求:方法所在的类必须是public
* 方法本身必须是public,而且是无参无返回值的,静态的
@Test
public void test(){
System.out.println("Hello");
}
@Before
public void test1(){
System.out.println("hi");
}
@After
public void test2(){
System.out.println("Test之后");
}
@BeforeClass
public static void test3(){
System.out.println("嘿嘿");
}
@AfterClass
public static void test4(){
System.out.println("嘿哈");
}
View Code
自定义注释
* 枚举看成是类
* 注解看成是接口
*
* 注解:
* (1)声明
* (2)使用
* (3)读取
*
* 一、自定义注解
* 1、语法格式:
* 【修饰符】 @interface 注解名{
* }
*
* 2、加元注解说明一下
* 元注解:注解注解的注解,给注解加的注解。它们在java.lang.annotation包下
* (1)@Target
* @Target(ElementType.xx)
* @Target({ElementType.xx,ElementType.xx,...})
* ElementType是一个枚举类型,有很多常量对象:例如:TYPE,METHOD(方法),FIELD(属性),CONSTRUCTOR....
* TYPE(包含 Class, interface (including annotation type), or enum declaration )
* @Target作用:限制自定义的注解的使用的目标位置
*
* (2)@Retention
* @Retention(RetentionPolicy.SOURCE):源代码阶段 该注解只能被编译器读取
* @Retention(RetentionPolicy.CLASS):字节码阶段 该注解只能被编译器和类加载器读取
* @Retention(RetentionPolicy.RUNTIME):运行时阶段 该注解可以在运行时仍然被读取
*
* SOURCE < CLASS < RUNTIME
*
* @Retention的作用:限制自定义注解的寿命,可以“滞留”到什么阶段
* RetentionPolicy也是枚举类型,常量对象只有三个:SOURCE,CLASS,RUNTIME
*
* (3)@Documented
* 标记某个注解是否可以被javadoc读取到API中。
*
* (4)@Inherited
* 标记某个注解是否可以被子类继承
*
*/
package com.atguigu.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class TestDefineAnnotation {
public static void main(String[] args) {
//读取MyClass类上面的注解,用到了反射
Class clazz = MyClass.class;
MyAnnotation my = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
System.out.println(my);
Class clazz2 = MySub.class;
MyAnnotation my2 = (MyAnnotation) clazz2.getAnnotation(MyAnnotation.class);
System.out.println(my2);
}
}
//@YoursAnnotation
class MyClass{
//@YoursAnnotation //不能在属性上使用,因为它规定了只能使用在METHOD即方法上
@MyAnnotation
private String filed;
@MyAnnotation
@YoursAnnotation
public void test(){
}
}
class MySub extends MyClass{
}
@Inherited //标记这个注解可以被子类继承;
@Retention(RetentionPolicy.RUNTIME) //可以在运行时阶段读取;
@interface MyAnnotation{ //自定义一个注解;
}
@Documented
@Target(ElementType.METHOD) //限制自定义注解使用的目标位置
@Retention(RetentionPolicy.SOURCE) //只能被编译器读取;
@interface YoursAnnotation{
}
View Code
* 自定义注解
*
* 1、语法格式:
* @元注解
* 【修饰符】 @interface 注解名{
* }
*
*
* @元注解
* 【修饰符】 @interface 注解名{
* 配置参数
* }
*
* 没有配置参数的注解:
* (1)@Override
* (2)@Deprecated
* (3)@Documented
* (4)@Inherited
* (5)@Test
*
* 有配置参数的
* (1)@SuppressWarnings(xx)
* (2)@Target(xx)
* (3)@Retention(xx)
* (4)@WebServlet(xx)
*
* 1、配置参数的声明
* (1)声明格式:
* 数据类型 参数名();
* (2)配置参数在声明时,可以有默认值
* 数据类型 参数名() default 默认值; 如 String info() default "atguigu";
* (3)数据类型
* 注解的配置参数的数据类型的要求:8种基本数据类型,4种引用数据类型(String,Class,枚举,注解)
* 可以是它们的数组类型,例如:int[],String[],枚举类型[]等
*
* 2、如果有配置参数,在使用时
*(1) @注解名(参数名1 = 参数值1,参数名2 = 参数值2,。。。。)
*(2)如果这个注解只有一个配置参数,并且它的名字叫做value,那么可以省略value=
*
*换句话说,声明配置参数时,参数名首先考虑value
*
* 3、读取配置参数值时, 变量 = 注解对象.参数名()
*
*
* 回忆:default
* (1)switch
* (2)接口
* (3)注解配置参数的默认值
*
* 数据类型:
* (1)数据类型有哪些:
* (2)变量的数据类型: 都可以
* (3)属性的数据类型什么要求: 都可以
* (4)形参的数据类型什么要求: 都可以
* (5)返回值类型的类型有什么要求: 都可以
* (6)switch(表达式)中表达式的类型要求:4种基本数据类型,2种引用数据类
* (7)注解的配置参数的数据类型的要求:8种基本数据类型,4种引用数据类型(String,Class,枚举,注解)
* 可以是它们的数组类型,例如:int[],String[],枚举类型[]等
*/
public class TestAnnotation2 {
public static void main(String[] args) {
@SuppressWarnings("rawtypes")
Class clazz = TestA.class;
AnnotationA my = (AnnotationA) clazz.getAnnotation(AnnotationA.class);
System.out.println(my);
String str = my.info(); //对象.方法 来进行调用;
System.out.println(str);
}
}
@AnnotationA(info = "atguigu", age = 22, value = 88.9) //赋值时像属性,变量
class TestA{ //只有一个参数时可以省略value =
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface AnnotationA{
String info() default "尚硅谷"; //可以有默认值
int age(); //配置参数的声明;
char gender() default '男';
double value();
}
异常
* 所谓异常:程序大多数情况下是可以正常,正确的运行,但是有的时候因为一些不可控的因素,导致程序运行异常,中断。
* 例如:复制文件时,因为目标盘空间不足; 聊天功能时,因为网络中断;* 计算两个数的商,用户输入的除数为0
1)语法错误; 2)逻辑错误 --->> 它们不是异常。。。
异常的作用:使得系统可以通过捕获异常对象,然后处理异常,使得程序继续运行,否则,如果一旦异常,程序就会挂了。使得程序更健壮。
* Java中是如何处理异常?(原理)
* 当某句代码发生异常时,程序会在这句代码处“停”下来(下面的代码是无法执行的),
然后JVM(大多数是JVM,有的时候也可能是程序中自己new)会创建一个“合适类型的异常的对象”,并且“抛”出来;
JVM会在该句代码的“外围”搜索是否有"try..catch"可以“捕获”这个异常,如果可以“捕获”那么程序从"try..catch"下面继续运行,
如果没有找对应的"try..catch",或者先有的"try..catch"无法“捕获”,
那么程序会把这个异常对象“抛”给“上级”,如果上级可以“捕获”,那么就从“上级”的"try..catch"下面继续运行,
否则接着往上抛,一直到main,如果main也“捕获”不了,就挂了。
异常的类型
* 异常的类型:
* java.lang.Throwable:Throwable 类是 Java 语言中所有错误或异常的超类。
* (1)只有当对象是此类(或其子类之一)的实例时,才能通过 Java 虚拟机或者 Java throw 语句抛出。
* (2)只有此类或其子类之一才可以是 catch 子句中的参数类型。
*
* “抛”:JVM抛,throw抛
* “抓,捕获”:catch
*
* 两个子类的实例,Error 和 Exception,通常用于指示发生了异常情况。
* 通常,这些实例是在异常情况的上下文中新近创建的,因此包含了相关的信息(比如堆栈跟踪数据)。
*
* 分为:
* Error:错误,严重的异常,用于指示合理的应用程序不应该试图捕获(catch)的严重问题。
* 例如:VirtualMachineError的两个子类: OutOfMemoryError, StackOverflowError
* Exception:异常
* 非受检异常/运行时异常:RuntimeException及其它的子类
* 受检异常/编译时异常:除了运行时异常,剩下的都是编译时异常
*
* 编译器在检查程序时,遇到你throw或throws出RuntimeException,编译器不会强制要求你编写try..catch或继续throws处理;
* 编译器在检查程序时,遇到你throw或throws出非运行时异常,那么编译器会强制要求你编写try...catch或继续throws否则编译不通过。
*
Throwable是所有错误和异常的父类,超类。
Exception是所有异常的父类,它分为RuntimeException和非RuntimeException。
try..catch..finally形式有三种:1) try..catch; 2) try...catch..finally; 3) try..finally
try...catch
* try...catch
* 1、语法格式:
* try{
*
* 可能发生异常的语句块;
*
* }catch(异常类型1 异常名){
* 处理该异常的代码;
* }catch(异常类型2 异常名){ //catch -->> catch --> 一定是有先后顺序的,从子类---->>>父类,高级的
* 处理该异常的代码;
* }catch(异常类型3 异常名){
* 处理该异常的代码;
* }
* ....
*
* try..catch的执行过程:
* (1)如果try中的代码没有异常,那么try中的代码执行完,正常执行try..catch下面的代码
* (2)如果try中的代码发生异常,首先,try中发生异常那句代码 后面的代码是无法执行,其次,在try中抛出一个
* 异常对象,catch会按从上到下,依次尝试“捕获”,如果有一个“捕获”了,下面的catch就不看。
* 所有要求子异常类型写上面,父异常类型写下面。
* (3)如果try中的代码发生异常,并且所有的catch都没有“捕获”,那么try..catch下面的代码就无法执行了,
* 会把异常对象抛出“上级——调用者”,如果已经是最上级(main),就挂了。
*
* 这个特点有的像:
* if...else if....
*
*
*
* 提示:把字符串类型的数字转成int的值
* Integer.parseInt(字符串)
try...catch...finally
* try...catch...finally
* 2、语法格式:
* try{
*
* 可能发生异常的语句块;
*
* }catch(异常类型1 异常名){
* 处理该异常的代码;
* }catch(异常类型2 异常名){
* 处理该异常的代码;
* }catch(异常类型3 异常名){
* 处理该异常的代码;
* }finally{
* 无论try中是否发生异常,也不管catch是否能够捕获异常,finally中一定要执行。
* }
*
* finally块中一般编写:释放资源,断开连接等代码。
*
*
* 面试题:final,finally,finalize的区别?
* final是修饰符,修饰类,表示不能被继承,修饰方法,表示不能被重写,修饰变量,表示值不能被修改是常量。
* finally:是try..catch..finally的一部分,无论try中是否发生异常,也不管catch是否能够捕获异常,finally中一定要执行
* finalize:是一个方法名,在Object类中,表示当对象被“垃圾回收器GC”回收之前调用,有它在就不回收了,只有第一次有效,第二次无效会被gc回收。
* 形式:
* try..catch
* try..finally
* try..catch...finally
public static void main(String[] args) {
int num3 = test();
System.out.println("num3 = " + num3); //1
}
public static int test(){
int result = 0;
try {
result = 1/1;
System.out.println("result = " +result); //1
return result;//(1)先把1,load到“方法的返回值存放区”(3)再结束当前方法,返回“方法的返回值存放区”的值
} catch (Exception e) {
return result;
}finally{
result++;//(2)result变量自增,变成2,这个2就不会放到“方法的返回值存放区” //如果变成return result++; 结果还是1 ;如果是return 3; 它就变成3了
System.out.println("result = " + result); //2
}
* 结论:
* (1)finally中的部分无论如何都要执行
* (2)如果finally中有return,以finally中的return语句为主
* (3)如果finally中无return,以try或catch中的return语句为主
*/
考到try...catch...finally和return一起的时候:
(1)finally中代码,无论如何一定要执行,不管是否发生异常,也不管是否catch住异常;
(2)如果finally中没有return语句,那么就先执行finally,然后再回去执行try或catch中的return语句,第二个作用“结束当前方法”,返回值不受finally影响;
(3)如果finally中有return语句,那么就执行finally中的return语句,相当于try和catch中return语句“失效”。
throws
throws:显式声明当前方法中,没有处理的异常,由调用者来处理,特别是编译时异常
如果方法中有产生编译时异常,而又未处理,那么必须加throws声明,否则编译不通过
如果方法中有产生运行时异常,而又未处理,那么可以加throws也可以不加,因为编译期间检测不到运行时异常,编译可以通过。
* throws:
* 1、用于在声明方法时,显式的声明当前方法中没有处理的异常,要调用者来处理。
* 调用者在使用有throws的方法时,用try...catch就知道该catch什么更具体异常,否则就按Exception
用上throws(你得知道要抛出的是什么异常如ArithmeticException),写在方法名的后边,你再try...catch.. 选择try里边的代码右键选择Sound with 选择try,
它就知道要抛什么异常了,不然它只会抛Exception异常。
*
* 2、语法格式:
* 【修饰符】 返回值类型 方法名(【形参列表】)throws 异常列表{
* }
*
* 异常列表可以写好几个,用,分割
*
* 3、关于方法重写
* (1)方法名和形参列表必须相同
* (2)返回值类型
* 基本数据类型和void:必须一致
* 引用数据类型:<= 子类重写方法的返回值类型<=父类被重写方法的返回值类型
* (3)权限修饰符:>= 子类重写方法的权限修饰符的可见性范围 >= 父类被重写方法的权限修饰符的可见性范围
* (4)其他修饰符: 哪些不能重写 static,final,private
* (5)抛出的异常列表的类型:<= 子类重写方法抛出的异常类型 <= 父类被重写方法抛出的异常类型
*/
public class TestThrows {
public static void main(String[] args) {
try {
divide(1, 0);
} catch (ArithmeticException e1) {
e1.printStackTrace();
}
try {
copy("1.txt", "2.txt");
} catch (FileNotFoundException e) {
e.printStackTrace();
}
Father f = new Son();//多态引用
try {
f.test(); //编译时按照父类Father,运行时按子类Son,子类抛出RuntimeException异常,Exception要能够捕获到
} catch (Exception e) { //反过来按照子类抛出的Exception,这个时候发现catch就捕获不了
e.printStackTrace();
}
}
public static int divide(int a, int b) throws ArithmeticException{
return a/b;
}
public static void copy(String srcFilePath, String destFilePath) throws FileNotFoundException{
FileInputStream fis = new FileInputStream(srcFilePath);
FileOutputStream fos = new FileOutputStream(destFilePath);
}
}
class Father{
public void test()throws Exception{
}
}
class Son extends Father{
public void test() throws RuntimeException{ //子类的抛出的异常类型要比父类的小
//要保证子类抛出的异常父类能够接住
}
}
View Code
throw用于手动抛出异常对象
* 大多数异常对象是JVM根据情况抛出。有的时候需要手动抛出异常,
* throw:用于手动抛出异常对象
* 语法结构:
throw 异常对象;
可以代替return语句,即带回异常信息,而且可以结束方法的执行
public class TestThrow {
public static void main(String[] args) {
Account account = new Account();
try {
account.withdraw(100);
System.out.println("取款成功");
} catch (Exception e) {
System.out.println(e.getMessage()); // 打印的是条件不满足时抛出的异常,给用户看的
//e.printStackTrace(); //直接打印出红色异常信息,给开发者看的;
}
System.out.println("余额为:" + account.getBalance());
}
}
class Account{
private double balance = 1000;
public double getBalance() {
return balance;
}
public void setBalance(double balance) {
this.balance = balance;
}
public void withdraw(double amount){
if(amount < 0){
//Illegal不合法,Argument参数
IllegalArgumentException e = new IllegalArgumentException("取款金额输入有误");
throw e;
}if(amount > balance){
throw new RuntimeException("余额不足");
}
balance -= amount;
}
}
自定义异常:
* (1)要继承Throwable或它子类
* 一般都继承Exception(编译时异常),或者RuntimeException(运行时异常)
* (2) 异常名要见名知意
* (3)尽量保留父类的两个构造器:一个是无参构造,一个是为message赋值的构造器
* (4)自定义异常必须手动用throw来抛出,JVM无法给你自动抛出
*
* 一个异常:
* (1)类型要见名知意
* 例如:ArrayIndexOutOfBoundsException
* ClassCastException
* FileNotFoundException
*
* (2)自己的message消息
* 异常对象名.getMessage()可以获取
(3)堆栈跟踪信息
* 异常对象经历的抛出路线,从哪个方法到哪个方法
* 异常对象名.printStackTrace(); //Trace痕迹
* System.err:异常信息,默认是红色的
* System.out:普通信息
* System.err和System.out是两个线程,谁先抢到谁先打印
public class TestMyException {
public static void main(String[] args) {
try {
regist("admin", 22, "123@qq.com");
System.out.println("注册成功");
} catch (UsernameExistException e) {
e.printStackTrace();
System.out.println(e.getMessage());
}
}
public static void regist(String username, int age, String email) throws UsernameExistException{
//做一个假的注册,假设我的数据库已经存"admin"
if("admin".equals(username)){
throw new UsernameExistException("用户名已存在");
}
}
}
class UsernameExistException extends Exception{
public UsernameExistException(){
super();
}
public UsernameExistException(String message){
super(message);
}
}
异常类型
//下标越界
public class TestArrayIndexOutOfBoundsException {
public static void main(String[] args) {
int[] arr = new int[0];
try {
System.out.println(arr[0]);
} catch (Exception e) {
e.printStackTrace();//标准的异常信息的打印方法,信息比较全,(1)类型(2)message(3)堆栈跟踪信息
//或
System.out.println(e.getMessage());//只有message
}
}
}
View Code
运行时异常
异常栈e.printStank
NullPointerException:空指针异常,当对象是null,却用对象调用方法,属性等。
ArrayIndexOutOfBoundsExceptiom:数组下标越界异常,当下标的值超过[0,数组的长度-]的范围
ClassCastException:类型转换异常,当对象不是该类型的实例时
NumberFormatException:数字格式化异常,当把一个非数字的字符串转为数字
ArithmeticException:算术异常,例如当除一个0时
Java可能导致内存泄露的错误代码或者用简单代码演示内存溢出
public class TestOutOfMemoryError {
public static void main(String[] args) {
Object[] arr = new Object[Integer.MAX_VALUE];
System.out.println("Integer.MAX_VALUE =" + Integer.MAX_VALUE);
}
}
java.lang.OutOfMemoryError: Requested array size exceeds VM limit
----------------------------------------------------------------------------------
public class TestStackOverflowError {
public static void main(String[] args) {
test();
}
public static void test(){
test();
}
}
java.lang.StackOverflowError
错误异常从最下看
最后一个Caused by :xxx,然后再从下往上