(7)抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常)

1.抽象类中可以没有抽象方法,但有抽象方法的类一定是抽象类。
2.接口中成员的定义规则
interface InterDemo{
    public static final int Num=4;
    public abstract void  show();
}
接口中只能定义public static final全局常量和和public abstract抽象方法,public static final可以省略,public abstract也可省略
interface  InterDemo{
    int NUM=4;
    void show();
}
所以实现接口的类的方法必须是public的,权限不能小于抽象方法的权限。
3.java中可以多继承,但仅限于接口之间
思考:为什么类不能多继承,如果C继承A,同时继承B,在A和B中分别有一个一样的方法,当A实例化对象调用这个方法时,不知道该调用哪个方法。但在接口中,就可以避免这种情况,因为接口中的方法都是抽象的,接口C继承接口A和B时,在另一个类中实现接口C时,必须重写C中全部的抽象方法,如果A和B中的抽象方法一模一样,则在类中重写该方法时,同时覆盖了A和B中的这个抽象方法,不会冲突。
但有个情况下接口不能多继承,即在A和B中的同名方法,参数列表相同,只是返回值类型不同,这样在实现C接口的类中,重写A和B中的这个方法,会得到两个同名方法,参数列表相同,返回值类型不同,这不是重载,是不允许在同个类中出现的,所以这种情况是不能存在的,综上,接口是可以多继承的。
4.接口的作用:
接口向外暴露规则
接口可以扩张程序的功能
接口降低了程序间的耦合性,使开发并发执行,而不是串行执行
5.继承与实现
继承是is a 关系    实现是like a 关系     聚集(聚合、组合)是has a 关系
继承是搞主业,实现是搞副业
6.多态的体现:父类的引用指向子类对象;父类的引用可以接受子类类型的对象
多态的好处:扩展了程序的功能    方便操作一批对象
多态的前提:存在继承或实现,并且存在覆盖
多态的弊端:只能用父类的引用访问父类中被重写后的方法
7.基本数据类型里的类型提升,在引用数据类型中叫做向上转型,强制类型转换用于向下转型
8.多态中:
      Fu  f=new Zi(); //这就是多态,引用f即可表现Zi类的类型,也可表现Fu类类型
      f.method();
多态中,调用非静态成员方法的特点:(常用,因为有重载)
在编译时期,jvm参阅引用型变量所属的类中是否有这些方法,如果有则编译通过,否则报错
在运行时期,jvm参阅引用型变量所指向的对象中是否有这些方法,如果有,执行这些对象中的方法,如果没有,执行引用型变量所属类中的方法
简单说就是,编译期间参阅左边类(参见例①),运行期间参阅右边类(参见例②)

多态中,调用静态成员方法的特点:(不常用,面试,静态方法很少重载)
无论编译与运行,都参阅引用型变量所属的类(左边)
(参见例③)

多态中,调用成员变量的特点:(不常用,面试,重载成员变量没意义)
无论编译与运行,都参考引用型变量所属的类(左边) (参见例④⑤)
****************************************************************************
实例:Test.java
class Fu{
void method1(){
System.out.println("fu.....method_1");
}
void method2(){
System.out.println("fu.....method_2");
}
}
class Zi extends Fu{
void method1(){
System.out.println("Zi.....method_1");
}
void method3(){
System.out.println("Zi.....method_3");
}
}
//① 多态中,调用非静态成员方法的特点:编译期间参阅左边类
public class Test{
public static void main(String []args){
Fu f=new Zi();
f.method1();
f.method2();
f.method3(); 
}
}
编译结果:


 //② 运行期间参阅右边类
public class Test{
public static void main(String []args){
Fu f=new Zi();
f.method1();
f.method2();
}
}
运行结果:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
 
//③ 多态中,调用静态成员方法的特点:无论编译与运行,都参阅引用型变量所属的类(左边)
class Fu{
static void method1(){
System.out.println("fu.....method_1");
}
void method2(){
System.out.println("fu.....method_2");
}
}
class Zi extends Fu{
static void method1(){
System.out.println("Zi.....method_1");
}
}
public class Test{
public static void main(String []args){
Fu f=new Zi();
f.method1();
f.method2();
}
}
运行结果:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
 
//④ 多态中,调用成员变量的特点:无论编译与运行,都参考引用型变量所属的类(左边)
class Fu{
int num=3;
}
class Zi extends Fu{
int num=5;
}
public class Test{
public static void main(String []args){
Fu fu=new Fu();
System.out.println(fu.num);
Zi z=new Zi();
System.out.println(z.num);
Fu f=new Zi();
System.out.println(f.num);
}
}
运行结果:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
 
//⑤ 多态中,调用静态成员变量的特点:无论编译与运行,都参考引用型变量所属的类(左边)
class Fu{
static int num=3;
}
class Zi extends Fu{
static int num=5;
}
public class Test{
public static void main(String []args){
Fu fu=new Fu();
System.out.println(fu.num);
Zi z=new Zi();
System.out.println(z.num);
Fu f=new Zi();
System.out.println(f.num);
}
}
//运行结果同上:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰

****************************************************************************

9.内部类的访问规则:
内部类可以直接访问外部类的成员;(因为内部类中默认有外部类的引用   外部类名.this)
外部类要想访问内部类,必须创建内部类的对象,然后访问。
实例:
class Outer{
private int x=5;   //③
class Inner {  //内部类直接定义在外部类的成员位置上
int x=6;           //②
void function(){
int x=7;      //①
System.out.println(x); //访问①
System.out.println(this.x); //访问②
System.out.println(Outer.this.x); //访问③
}
}
void method(){
Inner in=new Inner();  //外部类要想访问内部类,需要创建内部类的对象
in.function();
}
}

class Test3{
public static void main(String[] args) {
//在外部其他类中访问另一个类的内部类
//方法一、创建外部类的对象,调用外部类的方法,在外部类的方法中访问内部类
Outer out=new Outer();
out.method();
//方法二、直接创建内部类的对象(前提,内部类没有被pivate)不常用
Outer.Inner in=new Outer().new Inner();
in.function();
}
}

10.在其他类中直接访问非静态内部类:(少用,因为内部类作为外部类的成员,考虑到封装性,一般用private修饰,这也是 唯一类可以被private修饰的情况
Outer.Inner in=new Outer().new Inner();
在外部其他类中,直接访问静态内部类的非静态方法:  ④
new Outer.Inner(). function ();
在外部类中,直接访问静态内部类的静态成员:         

Outer.Inner.
function ();
注意:1>如果内部类的成员有静态的,那么内部类也一定要设为静态的
    (因为,外部类加载时,如果内部类不是静态的,那么内部类作为外部类的成员不会被加载,错过了加载类的机会,要想加载只有创建内部类的对象时加载,而此时内部类有静态成员只有因创建对象的需要而随类加载,违背静态的初衷<不必创建对象,直接通过类访问成员>)
2>外部类的静态方法访问内部类时,内部类也必须是静态的。
****************************************************
class Outer{
private int x=1;
static class Inner{
void function(){
System.out.println(x);
}
}
}
class Test {
public static void main(String[] args) {
new Outer.Inner().function ();
}
}
****************************************************
class Outer{
private int x=1;
static class Inner{
static void function(){
System.out.println(x);
}
}
}
class Test {
public static void main(String[] args) {
Outer.Inner.function ();
}
}
****************************************************
11.什么时候用内部类?
当一个类中需要直接访问另一个类中的成员时,就用内部类。(个人理解,当一个类的存在,应该以其他类的存在为依托时,用内部类)
一个例子,外部类好像一个人体,内部类好像一个个器官,这些器官封装了各种功能,当访问这些器官时,先要创建人体,这时器官就要作为人体的内部类。
12. 当内部类定义在外部类的局部时,比如在方法内,这时不能用成员修饰符修饰内部类。
这时还可以正常访问外部类中的成员,如果要访问该局部(方法区域中)中的变量时,变量必须是final修饰的,同样内部类要访问该方法接收的实际参数时,该参数也要是final的。

class Outer{
void method(){
    int x=3;      //定义在局部的内部类访问该局部中的变量,变量必须是final修饰的
   class Inner{
void function(){
System.out.println(x);
}
}
    new Inner().function();
}
}
class Test4 {
public static void main(String[] args) {
Outer out=new Outer();
out.method();
}
}
编译不能通过:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
同样如果要访问该局部中的形式参数时,该参数必须也是final修饰的
 class Outer{
void method(int y){    //定义在局部的内部类访问该局部中的变量,变量必须是final修饰的
   final  int x=3;    
   class Inner{
void function(){
System.out.println(x+y);
}
}
    new Inner().function();
}
}
class Test4 {
public static void main(String[] args) {
Outer out=new Outer();
out.method(6);
}
}
编译不能通过:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
  class Outer{
void method(final int y){   //定义在局部的内部类访问该局部中的变量,变量必须是final修饰的
   final  int x=3;    
   class Inner{
void function(){
System.out.println(x+y);
}
}
    new Inner().function();
}
}
class Test4 {
public static void main(String[] args) {
Outer out=new Outer();
out.method(6);  //虽然形参是final修饰的常量,但程序执行到这里时,method方法进栈,执行完后出栈
out.method(7);  //下一步同样进栈出栈,这是两个常量,并没有修改常量的值
}
}
运行结果:
Java笔记(7)——接口、异常、内部类 - snail - 蜗牛曰
 
s
13.匿名内部类是内部类的简写形式。(awt中用的比较多)
定义匿名内部类的前提:这个内部类继承父类或者实现接口
匿名内部类的格式:(这里隐藏了extends或implements,但这种关系依然存在,所以能重写)
new 父类名或者接口名{
                                      需要重写的方法
                                   }.重写的方法
匿名内部类其实就是子类或者实现接口的类的对象.(匿名内部类是吧类的定义和对象的创建一起做了)
匿名内部类适用于其要重写的方法少于3个的情况,多的话,代码的阅读性就很差
如果需访问重写的多个方法,就可以给这个匿名内部类起名字,这里只能用到其父类或所实现的接口的名字,用到了多态。  Fu   f=new 父类名或者接口名{
                          需要重写的方法
                          void method1(){ ……}
                          void method2(){ ……}
                  }
              f.method1();
              f.method2();
匿名内部类自始至终没有出现这个内部类的名字,所以简写的同时也就有了局限:
这里的method1、method2都必须是重写的方法,如果是匿名内部类特有的方法,则这里不能访问,因为,编译期间,参阅左边,jvm在f所属类Fu类中找不到那些方法,也不能向下转型,所以编译失败。如果想能调用,就得老老实实的用内部类,定义内部类继承父类或实现接口,然后在外部类的方法中创建对象,调用。
*************************************************
内部类转换为匿名内部类前: InnerClassTest.java
abstract class Heart{
abstract void beat();
}
class People{
private int age;
private String sex;
People(int age,String sex){
this.age=age;
this.sex=sex;
}
//内部类
class PersonHeart extends Heart{
void beat(){
System.out.println(age+"岁的"+sex+"人心脏跳动...");
}
}
//外部类访问内部类
void function(){
PersonHeart ph=new PersonHeart();
ph.beat();
}
}

class InnerClassTest{
public static void main(String []args){
People p=new People(20,"男");
p.function();
}
}
*************************************************
内部类转换为匿名内部类 AnonymousInnerClassTest.java
abstract class Heart {
abstract void beat();
}
class People {
private int age;
private String sex;
People(int age,String sex) {
this.age=age;
this.sex=sex;
}

/* class PersonHeart extends Heart {
void beat() {
System.out.println(age+"岁的"+sex+"人心脏跳动...");
}
}
*/
void function() {
//PersonHeart ph=new PersonHeart();
//ph.beat();
new Heart() {           //匿名内部类,没有名字直接用父类或要实现的接口的名字
void beat() {
System.out.println(age+"岁的"+sex+"人心脏跳动...");
}
}.beat();
}
}

class AnonymousInnerClassTest {
public static void main(String []args) {
People p=new People(20,"男");
p.function();
}
}
14.异常是对问题的封装,封装成对象。
严重的问题(如不可治愈的疾病):封装到Error中
不严重的问题(如感冒发烧):封装到Exception中
二者有一些共性,从中抽取得到父类Throwable
15异常的处理方法:
e.getMessage(); //打印异常的描述信息
e.toString();       //打印异常对象的名字:异常描述信息
e.printStackTrace();  //打印异常的堆栈追踪信息,jvm默认的异常处理方式
16.在可能出现异常的方法后用throws关键字进行声明,尽量声明具体的异常,后面调用该方法时必须进行捕获或者声明抛出,如果声明抛出,发生异常时则抛给虚拟机,程序终止,如果不抛出也不捕获就编译失败。
17.方法后声明几个异常,后面调用方法时就要用几个catch块处理,不要定义多余的catch块,如果异常中有继承关系,父类异常放在下面。
异常的几种格式:
1>try{
...
     }catch(Exception e){
...
    }
2>try{
...
     }catch(Exception e1){
...
     } catch(Exception e2){
...
     }
3> try{
...
     }catch(Exception e){
...
    }finally{
...
    }
4> try{
...
     }finally{
...
    }
18.throws与throw
throws:用在方法上,声明可能抛出的异常类,后跟异常类名
throw  :用在方法内,抛出异常对象,后用new创建异常对象并抛出
19.实例
//1>没有异常处理
class Demo {    
int div(int a,int b)  {          
return a/b;
}
}

class ExceptionDemo1  {
public static void main(String[] args)  {
System.out.println(new Demo().div(4,0));
System.out.println("over");
}
}
编译没有语法错误,运行结果:抛出异常,没有打印over,程序终止。
Java笔记(7)——抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常) - snail - 蜗牛曰
 
//2>加上异常处理
class Demo {    
int div(int a,int b)  {         
return a/b;
}
}

class ExceptionDemo2  {
public static void main(String[] args)  {
try {
System.out.println(new Demo().div(4,0));
}catch (ArithmeticException e) {
System.out.println("e.getMessage()....."+e.getMessage());
System.out.println("e.toString()......"+e); //e.toString();
System.out.print("e.printStackTrace().....");
e.printStackTrace();
}
System.out.println("over");
}
}
运行结果:抛出异常信息,程序继续执行,打印出over
Java笔记(7)——抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常) - snail - 蜗牛曰
 

// 3>自定义异常
class FushuException extends Exception{
private String msg;
FushuException(String msg){
this.msg=msg;
}
public String getMessage(){
return msg;
}
}   
class Demo{
int div(int a,int b) throws ArithmeticException,FushuException{
if (b<0)
throw new FushuException("除数是负数啦!");
return a/b;
}
}

class ExceptionDemo {
public static void main(String[] args) {
try{
System.out.println(new Demo().div(4,-2));
}catch(FushuException e){
System.out.println(e.getMessage());
}catch (ArithmeticException e){
System.out.println("e.toString()......"+e); //e.toString();
}
System.out.println("over");
}
}
运行结果:
Java笔记(7)——抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常) - snail - 蜗牛曰
 
// 优化
/*
class FushuException extends Exception{
private String msg;
FushuException(String msg){
this.msg=msg;
}
public String getMessage(){
return msg;
}
}   */
//Exception 继承 throwable,父类已经把上面的事情做完了,所以可以简化
class FushuException extends Exception{
FushuException(String msg){
super(msg);
}
}

class Demo{
int div(int a,int b) throws FushuException{
if (b<0)
throw new FushuException("除数是负数啦!");
return a/b;
}
}

class ExceptionDemo {
public static void main(String[] args) {
try{
System.out.println(new Demo().div(4,-2));
}catch(FushuException e){
System.out.println(e.getMessage());
}
catch (ArithmeticException e){
System.out.println("e.toString()......"+e); //e.toString();
}
System.out.println("over");
}
}
Java笔记(7)——抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常) - snail - 蜗牛曰
 
// 4>如果想获取是负数的除数,需要自己手动定义方法
class FushuException extends Exception{
private int value;
FushuException(String msg,int value){
super(msg);
this.value=value;
}
public int getValue(){
return value;
}
}

class Demo{
int div(int a,int b) throws ArithmeticException,FushuException{
if (b<0)
throw new FushuException("除数是负数啦!",b);
return a/b;
}
}

class ExceptionDemo {
public static void main(String[] args) {
try{
System.out.println(new Demo().div(4,-2));
}catch(FushuException e){
System.out.println(e.getMessage()+"除数是:"+e.getValue());
}catch (ArithmeticException e){
System.out.println("e.toString()......"+e); //e.toString();
}
System.out.println("over");
}
}
运行结果:
Java笔记(7)——抽象类、接口、多态、内部类(匿名内部类)、异常(自定义异常) - snail - 蜗牛曰
 
//5>实际执行过程中调用div方法可能发生异常,所以要事先声明可能抛出异常,
//有两种情况:
  (1)编译时异常,前面声明可能抛出异常,后面调用时就必须要处理异常,如果不处理则不能通过编译
(2)运行时异常RuntimeException,当程序遇到异常无法处理,必须停止程序,修正代码时用的,下面的ArithmeticException就是RuntimeException的子类。
(1)class Demo{
int div(int a,int b) throws FushuException{   //编译时异常在函数内抛出,必须在方法上声明抛出
if (b<0) //它的调用者必须做出处理:抛出或捕捉
throw new FushuException("除数是负数啦!");
return a/b;
}
}
(2)RuntimeException在函数内抛出,函数上也不必声明
class Demo {    
int div(int a,int b)  throws  ArithmeticException {     //这里不用声明抛出异常
if (b==0){
throw new ArithmeticException();  
return a/b;
}
}
20.异常练习
//毕老师用电脑上课,电脑可能出现异常(蓝屏。冒烟)
//思路:
/*
1.毕老师和电脑是两个对象,创建Teacher类和Computer类。可以把一个Computer类的对象作为Teacher类的一       个属性。
Teacher
   ---String name
   ---Computer computer
   =====void prelect()
   =====void test ()
Computer
   ----int state 状态码
   ====void run()
   ====void reset()
2.定义异常:LanPingException 、MaoYanException
3.prelect方法调用run方法,对可能发生的异常进行处理.蓝屏异常比较好处理。
MaoYanException毕老师不能处理,貌似应该让MaoYanException继承RuntimeException
但如果这时抛出给jvm,相当于抛给校长,这样的话没有什么意义,校长直接处理的是
老师的异常,所以可以把MaoYanException转换为老师的课时异常,让校长处理
(分层思想:本层的异常处理后,向外暴露外层能识别的异常)
4.定义KeShiException ,在prelect方法中对run方法可能发生的MaoYanException的处理
是抛出KeShiException,然后在prelect方法上声明,让jvm去处理
*/
//1
class Teacher{
private String name;
private Computer computer;
Teacher(String name){
this.name=name;
computer=new Computer();
}
public void prelect() throws KeShiException{
try{
computer.run();
}catch (LanPingException e){
System.out.println(e.getMessage());
computer.reset();
}catch (MaoYanException e){
System.out.println(e.getMessage());
test();  //注意不能放在throw后面,throw也是程序结束的标志
throw new KeShiException("因为电脑冒烟不能完成课时");
}
System.out.println(this.name+"上课");
}
public void test(){
System.out.println("做练习");
}
}

//2
class Computer{
private int state=3;  //标识电脑的状态码
public void run() throws LanPingException,MaoYanException{
System.out.println("电脑运行");
if (state==2){
throw new LanPingException("蓝屏了...");
}
if (state==3){
throw new MaoYanException("冒烟了...");
}
}
public void reset(){
System.out.println("重启电脑");
}
}
//3
class LanPingException extends Exception{
LanPingException(String message){
super(message);
}
}
//4
class MaoYanException extends Exception{
MaoYanException(String message){
super(message);
}
}
//5
class KeShiException extends Exception{
KeShiException(String message){
super(message);
}
}
//6
class ExceptionDemo5 {
public static void main(String[] args) {
try{
Teacher t=new Teacher("毕老师");
t.prelect();
}catch (KeShiException e){
System.out.println("换电脑或者放假");
}
}
}
21.覆盖时异常的特点 
1>.子类覆盖父类时,如果父类抛出异常,子类在覆盖父类的方法时,只能抛出父类异常或该异常的子类异常
2>.如果父类或接口没有异常抛出,那么子类在覆盖父类的方法时也不能抛出异常
  如果子类发生异常,必须进行try处理,绝对不能抛。
ExceptionInOverride.java
class AException extends Exception
{}
class BException extends AException
{}
class CException extends Exception
{}

class Fu {
void run() throws AException
{}
}
class Zi extends Fu{
void run() throws BException    //子类重写父类的方法时,只能抛出父类的异常或异常的子类异常
{}
}
class Test{
void function(Fu f) {
try{
f.run();
}catch (AException e){}
System.out.println("over");
}
}

class ExceptionInOverride{
public static void main(String []args){
Test t=new Test();
t.function(new Zi());
}
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值