day10.final-内部类-异常-Object类
课前回顾:1.抽象:abstract2.注意:抽象方法所在的类一定是抽象类抽象类中不一定非得有抽象方法(还可有构造,成员变量,成员方法)抽象类不能直接new对象,需要创建子类对象来实现子类重写抽象父类时,需要重写父类中所有的抽象方法,除非子类也是一个抽象类3.多态:前提:必须有子父类继承关系还有就是接口实现关系必须有方法重写,没有方法重写多态没有意义父类引用指向子类对象好处:当参数传递时,传递父类类型,到时候传递实参时,可以传递任何这个父类的子类,扩展性强弊端:不能调用子类特有功能转型:向上转型:默认的向下转型:强转 ->调用子类的特有方法关键字:instanceof 判断类型对象名 instanceof 类型 ->判断对象是否属于这个类型4.接口:标准关键字: interface(接口) implenments(实现)成员:jdk7:抽象方法:带abstract 不写也有成员变量:public static final ->常量 接口名直接调用jdk8:默认方法:带default的方法->可重写可不重写静态方法:带static的方法->接口名直接调用5.接口和抽象类的区别:相同点:两者都是作为继承的顶端不同点:抽象类一般作为父类使用:可以抽取共有的变量,成员方法等接口作为一个功能的标准:抽取的都是方法6.接口特点:接口可以多继承一个类可以实现一个或者多个接口一个类还可以继承一个父类的同时实现一个或者多个接口7.final关键字:a.被final修饰的类不能被继承b.被final修饰的方法不能被重写 不能和abstract一起使用今日重点:1.会使用final关键字2.会使用匿名内部类3.会使用throws处理异常4.会使用try...catch处理异常5.分清楚什么是编译时期异常,什么是运行时期异常
第一章.final关键字
1.概述:最终的,最后的
1.final修饰类
1.格式:public final class 类名{}2.特点:被final修饰的类,不能被继承的
public final class Animal {public void eat(){System.out.println("动物都要吃饭");}}
public class Dog extends Animal{//因为Animal类被final修饰了,所以不能被继承}
2.final修饰方法
1.格式:修饰符 final 返回值类型 方法名(参数){方法体return 结果}2.特点:被final修饰的方法不能被重写的3.注意:final和abstract不能同时修饰方法
public abstract class Animal {public final void eat(){System.out.println("动物都要吃饭");}/*final和abstract不能一起修饰方法,因为冲突final修饰的方法不能被重写abstract修饰的方法必须要被重写所以冲突*///public final abstract void drink();}
public class Dog extends Animal{/*被final修饰的方法不能被重写public void eat(){}*/}
3.final修饰局部变量
1.格式:final 数据类型 变量名 = 值2.特点:被final修饰的局部变量,不能被二次赋值,可以理解为是一个常量
public class Test01 {public static void main(String[] args) {final int i = 10;//i = 20;final修饰的变量不能被二次赋值final int j;j = 100;//属于给变量j第一次赋值//j = 200;//属于给j第二次赋值}}
4.final修饰对象
1.格式:final 类型 对象名 = new 类名()2.特点:被final修饰的对象地址值不能改变,但是对象的属性值可以变
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 class Test01 {public static void main(String[] args) {final Person p1 = new Person("柳岩", 36);System.out.println(p1);//地址值//p1 = new Person("金莲",32);p1被final修饰,地址值直接定死,不能改变地址值p1.setName("杨幂");p1.setAge(32);System.out.println(p1.getName()+"..."+p1.getAge());}}
5.final修饰成员变量
1.格式:final 数据类型 变量名 = 值2.特点:被final修饰的成员变量不能被二次赋值被final修饰的成员变量需要手动赋值
public class Person {final String name = "大郎";public Person() {//name = "大郎";}/* public Person(String name) {this.name = name;}*/public String getName() {return name;}/* public void setName(String name) {this.name = name;}*/}
小结:
final修饰类:不能被继承
final修饰方法:不能被重写
final修饰局部变量:不能被二次赋值
final修饰对象:地址值不能变,属性值可以改变
final修饰成员变量:需要手动赋值 不能被二次赋值
第二章.内部类
当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构最好使 用内部类。在Java中,允许一个类的定义位于另一个类的内部,前者称为内部类,后者 称为外部类。public class A{class B{}}B就是A的内部类A就是B的外部类Inner class一般用在定义它的类或语句块之内,在外部引用它时必须给出完 整的名称。Inner class的名字不能与包含它的外部类类名相同;分类:成员内部类(static成员内部类和非static成员内部类)局部内部类匿名内部类
1 静态成员内部类
1.格式:直接在声明内部类的时候加上static关键字即可类名{static class 类名{}}2.注意:a.类中可以定义属性,方法,构造等b.静态内部类可以被final abstract修饰被final修饰之后,不能被继承被abstract修饰之后,不能被newc.静态内部类不能调用外部类的非静态成员(静态不能直接调用非静态)d.还可以被四种权限修饰符所修饰3.如何调用静态内部类成员外部类类名.静态内部类类名 对象名 = new 外部类类名.静态内部类类名()
public class Person {public void eat(){System.out.println("人要吃饭");}//静态成员内部类static class Heart{public void jump(){System.out.println("心会跳");//new Person().eat();在静态内部类中调用外部类中非静态成员}}}
public class Test01 {public static void main(String[] args) {//外部类类名.静态内部类类名 对象名 = new 外部类类名.静态内部类类名()Person.Heart heart = new Person.Heart();heart.jump();}}
2 非静态成员内部类
1.格式:直接在声明内部类的时候不加上static关键字即可类名{class 类名{}}2.注意:a.类中可以定义属性,方法,构造等b.静态内部类可以被final abstract修饰被final修饰之后,不能被继承被abstract修饰之后,不能被newc.非静态内部类能调用外部类的非静态成员(非静态能直接调用非静态)d.还可以被四种权限修饰符所修饰3.如何调用非静态内部类成员外部类.内部类 对象名 = new 外部类().new 内部类()
public class Person {public void eat(){System.out.println("人要吃饭");}//非静态成员内部类class Heart{public void jump(){System.out.println("心会跳");//eat();在非静态内部类中调用外部类中非静态成员}}}
public class Test01 {public static void main(String[] args) {//外部类类名.静态内部类类名 对象名 = new 外部类类名.静态内部类类名()/*Person.Heart heart = new Person.Heart();heart.jump();*/Person.Heart heart = new Person().new Heart();heart.jump();}}
如果外部类的成员变量和内部类的成员变量以及局部变量重名,该如何区分?
public class Person {String name = "柳岩";class Heart{String name = "心脏";public void display(String name){System.out.println(name);//局部变量name->就近原则System.out.println(this.name);//内部类成员变量 nameSystem.out.println(Person.this.name);//外部类成员变量 name}}}
public class Test {public static void main(String[] args) {//外部类.内部类 对象名 = new 外部类().new 内部类()Person.Heart heart = new Person().new Heart();heart.display("涛哥");}}
3 局部内部类
1.可以在方法中,代码块中,构造方法中使用
public class Person {public void method(){//局部内部类class Heart{public void jump(){System.out.println("心在跳");}}new Heart().jump();}}public class Test01 {public static void main(String[] args) {Person person = new Person();person.method();}}
public interface USB {public abstract void open();}
public class Test {public static void main(String[] args) {USB usb = method();//多态usb.open();//调用的是实现类重写的方法}public static USB method(){class Mouse implements USB{@Overridepublic void open() {System.out.println("鼠标打开了");}}return new Mouse();}}
4.匿名内部类(重点)
1.是内部类的简化写法。它的本质是一个`带具体实现的` `父类或者父接口的` `匿名的` **子类对象**。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,a. 定义实现类b. 重写接口中的方法c. 创建子类对象d. 调用重写后的方法我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。2.可以定义的位置:可以在方法中,代码块中,构造方法中使用->匿名内部类也是局部的3.格式:new 父类/接口(){重写方法}.重写的方法;或者父类类型/接口类型 对象名 = new 父类/接口(){重写方法};对象名.重写的方法;4.注意:匿名内部类代表的是子类对象
public interface USB {public abstract void open();}
public class Test {public static void main(String[] args) {Mouse mouse = new Mouse();mouse.open();System.out.println("================");new USB(){@Overridepublic void open() {System.out.println("鼠标开启啦");}}.open();System.out.println("================");USB usb = new USB(){@Overridepublic void open() {System.out.println("鼠标开启啦啦啦啦啦了");}};usb.open();}}
2.2 匿名内部类复杂用法_当参数传递
public interface USB {public abstract void open();}
public class Test02 {public static void main(String[] args) {//method(new Mouse());//使用匿名内部类传递method(new USB() {@Overridepublic void open() {System.out.println("鼠标开启啦");}});}public static void method(USB usb){//USB usb = mouseusb.open();}}
![day10[final_内部类_异常_Object类] - 图1](/uploads/projects/liuye-6lcqc@vk53cd/98cc19a6bccfc436df89a916a7a75e82.png)
2.3 匿名内部类复杂用法_当返回值返回
public interface USB {public abstract void open();}
public class Test03 {public static void main(String[] args) {USB usb = method();usb.open();//重写的open}public static USB method(){//return new Mouse();return new USB() {@Overridepublic void open() {System.out.println("键盘开启");}};}}
![day10[final_内部类_异常_Object类] - 图2](/uploads/projects/liuye-6lcqc@vk53cd/92c43b04dd3584f92e1b8935348ba43d.png)
第三章.异常
1.异常介绍
1.已经见过的异常:ArrayIndexOutOfBoundsException:索引越界异常NullPinterException:空指针异常ClassCastException:类型转换异常2.概述:异常在java中其实是一个一个的类,一旦出现,代表我们的代码有问题3.异常体系:如下图
![day10[final_内部类_异常_Object类] - 图3](/uploads/projects/liuye-6lcqc@vk53cd/b5fef6382cd20ac913aeab93a1f9b2ee.png)
public class Demo01Exception {public static void main(String[] args) throws FileNotFoundException {int[] arr = new int[3];//System.out.println(arr[120]);//运行时期异常//FileInputStream fis = new FileInputStream("day10\\1.txt");//编译时期异常//错误int[] arr1 = new int[999999999];System.out.println(arr1[9]);}}
2.异常出现的过程
![day10[final_内部类_异常_Object类] - 图4](/uploads/projects/liuye-6lcqc@vk53cd/1e7fb53f160c79854605957f95ab138c.png)
3.创建异常对象(了解)
1.格式:throw new 异常对象()->创建异常对象并抛出
public class Demo03Exception {public static void main(String[] args) {String s = null;method(s);}public static void method(String s){if (s==null){//创建异常对象,throw代表抛出throw new NullPointerException("我的身体被掏空!");}System.out.println("哈哈哈哈");}}
4.异常处理方式(重点)
4.1 异常处理方式一_throws
1.格式:在方法声明上->参数后面,方法体左半个大括号前面throws 异常
public class Demo04Exception {public static void main(String[] args)throws FileNotFoundException {String s = "";method(s);System.out.println("涛哥涛哥涛哥涛哥");}public static void method(String s)throws FileNotFoundException{if (!s.endsWith(".txt")){//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}System.out.println("哈哈哈哈");}}
4.2 异常处理方式一_throws多个异常
1.格式:throws 异常,异常...2.注意:a.如果要抛多个异常,且多个异常之间有子父类继承关系,我们只需要throws一个父类即可b.如果要抛多个异常,先抛子类,再抛父类c.如果我们不知道要抛具体什么异常,我们可以直接抛Exception
public class Demo04Exception {public static void main(String[] args)throws Exception/*IOException*//*,FileNotFoundException*/ {String s = "";method(s);System.out.println("涛哥涛哥涛哥涛哥");}public static void method(String s)throws Exception/*IOException*//*,FileNotFoundException*/{if (s==null){//创建异常对象throw new IOException();}if (!s.endsWith(".txt")){//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}System.out.println("哈哈哈哈");}}
4.3 异常处理方式二_try…catch
1.格式:try{可能会出现异常的代码}catch(异常 对象名){异常的处理方式->将异常信息放到日志文件中}2.注意:如果try中的代码有问题,被catch到了,相当于代码变正常了,后续的代码还能继续执行如果try中的代码有问题,没有被catch到,相当于没将代码处理,默认就会给jvm处理
public class Demo06Exception {public static void main(String[] args) {String s = "";//添加功能try {add(s);} catch (FileNotFoundException e) {e.printStackTrace();}//删除功能System.out.println("删除");}public static void add(String s) throws FileNotFoundException {if (!s.endsWith(".txt")) {//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}}}
4.4 异常处理方式二_多个catch
1.格式:try{可能会出现异常的代码}catch(异常 对象名){异常的处理方式->将异常信息放到日志文件中}catch(异常 对象名){异常的处理方式->将异常信息放到日志文件中}catch(异常 对象名){异常的处理方式->将异常信息放到日志文件中}...2.注意:a.如果catch的多个异常之间有子父类继承关系,只catch一个父类即可b.如果catch的多个异常之间有子父类继承关系,先catch子类,再catch父类c.如果catch的多个异常之间有子父类继承关系,只catch一个Exception即可
public class Demo07Exception {public static void main(String[] args) {String s = "";//添加功能/*try {add(s);} catch (IOException e) {e.printStackTrace();//将异常具体信息打印到控制台上}catch (FileNotFoundException e){e.printStackTrace();//将异常具体信息打印到控制台上}*//* try {add(s);} catch (IOException e) {e.printStackTrace();//将异常具体信息打印到控制台上}*/try {add(s);} catch (Exception e) {e.printStackTrace();//将异常具体信息打印到控制台上}//删除功能System.out.println("删除");}public static void add(String s) throws /*FileNotFoundException,*//*IOException*/Exception {if (s==null){throw new IOException();}if (!s.endsWith(".txt")) {//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}}}
public class Demo08Exception {public static void main(String[] args) {String s = "";//添加功能try {String s1 = null;/*出现空指针异常->NullPointerException如果catch不到,相当于没有处理,后续代码会受到影响*/System.out.println(s1.length());add(s);} catch (FileNotFoundException e) {e.printStackTrace();}//删除功能System.out.println("删除");}public static void add(String s) throws FileNotFoundException {if (!s.endsWith(".txt")) {//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}}}
5.finally关键字
1.finally:代表的是一定要执行的代码2.用法:和try...catch结合使用try{可能会出现异常的代码}catch(异常 对象名){异常的处理方式->将异常信息放到日志文件中}finally{一定要执行的代码}
public class Demo09Exception {public static void main(String[] args) {String s = "";//添加功能try {String s1 = null;/*出现空指针异常->NullPointerException如果catch不到,相当于没有处理,后续代码会受到影响*/System.out.println(s1.length());add(s);} catch (Exception e) {e.printStackTrace();}finally {System.out.println("我一定要执行");}//删除功能System.out.println("删除");}public static void add(String s) throws FileNotFoundException {if (!s.endsWith(".txt")) {//创建异常对象,throw代表抛出throw new FileNotFoundException("文件没找到!");}}}
注:快捷键
如果有编译时期异常:我们可以使用alt+回车->快速生成try…catch
如果有运行时期异常:我们可以选中->ctrl+alt+T
public class Test01 {public static void main(String[] args) {int method = method();System.out.println(method);}private static int method() {try{String s = null;System.out.println(s.length());return 2;}catch (Exception e){e.printStackTrace();// System.out.println("我是catch");return 1;}finally {System.out.println("我一定要执行");//return 3;}}}
运行结果:我一定要执行1如果finally中再写一个return 3执行结果为我一定要执行3
finally的使用场景:
关闭资源当一个对象没有用时,GC(垃圾回收器)会将没有用的对象从内存中清理,释放内存
但是,有的对象GC清理不了,比如:IO流对象 Socket对象 数据库连接对象等,所以我们需要用完之后手动关闭资源,释放资源
所以,GC清理不了的对象,就需要我们再finally中手动清理
6.抛异常时注意的事项
1.问题:父类中的方法抛了异常,那么子类重写方法之后要不要抛?可抛可不抛父类中的方法没有抛异常,那么子类重写方法之后要不要抛?不抛
什么时候用try…catch 什么时候用throws
1.如果想不影响后面功能的执行,就可以用try…catch
2.如果方法之间有递进关系,我们可以先throws 但是到了最后一层,需要统一作用一个try…catch处理
7.自定义异常
需求:完成一个注册案例,如果注册失败,抛出RegisterException,提示:该用户已经被注册
步骤:1.定义一个字符串,表示已经注册过的用户名2.创建Scanner,调用next(),表示要注册的用户名3.和已有的用户名进行比较,如果内容一样,证明注册过了,显示注册失败,抛出注册失败异常4.否则注册成功
public class RegisterException extends Exception{public RegisterException() {}public RegisterException(String message) {super(message);}}
public class Test {public static void main(String[] args) throws RegisterException {//1.定义一个字符串,表示已经注册过的用户名String username = "root";//2.创建Scanner,调用next(),表示要注册的用户名Scanner sc = new Scanner(System.in);System.out.println("请您输入要注册的用户名:");String name = sc.next();//3.和已有的用户名进行比较,如果内容一样,证明注册过了,显示注册失败,抛出注册失败异常if (name.equals(username)){throw new RegisterException("注册失败!");}else{//4.否则注册成功System.out.println("注册成功");}}}
1.随便一个类
2.如果继承Exception,此自定义异常类为编译时期异常
如果继承RuntimeExecption,此自定义异常类为运行时期异常
3.提供有参和无参构造,方便设置异常提示信息
8.打印异常信息的三个方法
Throwable类中定义了一些查看异常信息的方法:- public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。- public String toString():获取异常的类型和异常描述信息(不用)。- public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。
public class Test02 {public static void main(String[] args) {String s = "";try {method(s);} catch (FileNotFoundException e) {//Throwable类中定义了一些查看异常信息的方法://- public String getMessage():获取异常的描述信息,原因(提示给用户的时候,就提示错误原因。//System.out.println(e.getMessage());//- public String toString():获取异常的类型和异常描述信息(不用)。//System.out.println(e.toString());//- public void printStackTrace():打印异常的跟踪栈信息并输出到控制台。e.printStackTrace();}}private static void method(String s) throws FileNotFoundException {if (!s.endsWith(".txt")){throw new FileNotFoundException("文件找不到");}}}
第四章.Object类
1.概述:所有的类的父类2.如果一个类没有明确写明extends 父类 默认的父类就是Object所有的类都会直接或者间接的去继承Object类
1.Object类中的toString方法
public String toString() {//返回该对象的字符串表示。return getClass().getName() + "@" + Integer.toHexString(hashCode());}1.如果我们的类中没有重写toString,那么直接输出对象名时,默认会调用Object类中的toString方法,输出的就是地址值2.如果我们的类中重写toString方法,默认会调用重写后的toString方法,所以我们重写之后,返回的应该是内容(属性值)总结:如果直接输出对象名,不想输出地址值的话,那么就在这个对象内部重写Object类中的toString方法,输出内容(和getxxx方法无关)
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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}}
2.Object类中的equals方法
Object类中的equals方法://判断两个对象是否相等public boolean equals(Object obj) {return (this == obj);}==:针对于基本类型,比较的是值针对于引用类型,比较的是地址值1.如果一个对象没有重写equals方法,调用equals方法时,是调用的Object类中的equals方法,比较的是地址值2.如果一个对象重写了equals方法,再比较地址值就没意义了,所以我们重写equals之后应该比较内容(属性值)
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;}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}/*问题1:如果传递的不是Person类型,向下转型会出现ClassCastException解决问题1:类型判断问题2:如果传递null咋整?解决问题2:先做一个非空判断,如果是null直接返回false问题3:如果传递自己呢?解决问题3:如果传递同一个对象,直接返回 true*//* @Overridepublic boolean equals(Object o) {//Object o = p2if (this==o){return true;}if (o==null){return false;}if (o instanceof Person){//向下转型Person p2 = (Person)o;return this.name.equals(p2.name) && this.age==p2.age;}return false;}*/@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Person person = (Person) o;return age == person.age &&/*Objects.equals也是比较的字符串内容可以防止空指针异常*/Objects.equals(name, person.name);}}
public class Test {public static void main(String[] args) {Person p1 = new Person("柳岩", 36);Person p2 = new Person("柳岩", 36);System.out.println(p1.equals(p2));ArrayList<String> list = new ArrayList<>();System.out.println(p1.equals(list));System.out.println(p1.equals(null));System.out.println(p1.equals(p1));/* String s = null;boolean b = s.equals("哈哈哈");System.out.println(b);*/boolean result = Objects.equals(null, "abc");System.out.println(result);}}
总结:
1.如果直接输出对象名不是地址值的话,而是属性值->重写toString
2.如果比较的时候想比较内容而不是地址值->重写equals
![day10[final_内部类_异常_Object类] - 图5](/uploads/projects/liuye-6lcqc@vk53cd/f1209ee45a2f3144bdb9974c4465c7b7.png)
