关闭

黑马程序员——Java 面向对象(下)

176人阅读 评论(0) 收藏 举报

-----------android培训java培训、java学习型技术博客、期待与您交流!------------  


多态



        多态可以简单理解为事物存在的多种体现形态

       

 

一、多态的体现

       1、父类的引用指向了自己子类的对象。 

        2、父类的引用也可以接收自己的子类对象。

如:   Animal a = new Cat();

        其中就将父类型的 a 引用指向了子类的对象。

 

二、多态的前提

       1类与类之间必须有关系,要么继承,要么实现

        2、存在覆盖。父类中有方法被子类重写。

 

三、多态的利与弊

        利:提高了程序的可扩展性和后期可以维护性。

        弊:只能使用父类中的引用访问父类中的成员。也就是说使用了多态,父类型的引用在使用功能时,不能直接调用子类中的特有方法

        如果此时父类的引用想要调用Cat中特有的方法,就需要强制将父类的引用,转成子类类型,向下转型。如:Cat  c =  (Cat) a ;

        注意:如果父类可以创建对象,如:Animal a = new Animal(); 此时,就不能向下转型了,Cat c = (Cat)a; 这样的代码就变得不容许,编译时会报错。所以千万不能出现这样的操作,就是将父类对象转成子类类型。

        我们能转换的是父类引用指向了自己的子类对象时,该引用可以被提升,也可以被强制转换。多态至始至终都是子类对象在做着变化。

下面就是一个多态的示例:

public class heima_animal
{
    public static void main(String[] args)
    {
        
        //向上类型转换
        Cat cat = new Cat();
        Animal animal = cat;
        animal.sing();

                
        //向下类型转换
        Animal a = new Cat();
        Cat c = (Cat)a;
        c.sing();
        c.eat();


        //编译错误
        //用父类引用调用父类不存在的方法
        //Animal a1 = new Cat();
        //a1.eat();
        
        //编译错误
        //向下类型转换时只能转向指向的对象类型        
        //Animal a2 = new Cat();
        //Cat c2 = (Dog)a2;
        


    }
}
class Animal
{
    public void sing()
    {
        System.out.println("Animal is singing!");
    }
}
class Dog extends Animal
{
    public void sing()
    {
        System.out.println("Dog is singing!");
    }
}
class Cat extends Animal
{
    public void sing()
    {
        System.out.println("Cat is singing!");
    }
    public void eat()
    {
        System.out.println("Cat is eating!");
    }
}


 

四、多态的特点


对象的多态性与函数的多态性(重载与覆盖)

重载与覆盖的区别:

重载:override可以翻译为覆盖,从字面就可以知道,它是覆盖了一个方法并且对其重写,以求达到不同的作用。对我们来说最熟悉的覆盖就是对接口方法的实现,在接口中一般只是对方法进行了声明,而我们在实现时,就需要实现接口声明的所有方法。除了这个典型的用法以外,我们在继承中也可能会在子类覆盖父类中的方法。在覆盖要注意以下的几点: 
1、覆盖的方法的标志必须要和被覆盖的方法的标志完全匹配,才能达到覆盖的效果; 
2、覆盖的方法的返回值必须和被覆盖的方法的返回一致; 
3、覆盖的方法所抛出的异常必须和被覆盖方法的所抛出的异常一致,或者是其子类; 
4、被覆盖的方法不能为private,否则在其子类中只是新定义了一个方法,并没有对其进行覆盖。 
覆盖:overload对我们来说可能比较熟悉,可以翻译为重载,它是指我们可以定义一些名称相同的方法,通过定义不同的输入参数来区分这些方法,然后再调用时,VM就会根据不同的参数样式,来选择合适的方法执行。在使用重载要注意以下的几点: 
1、在使用重载时只能通过不同的参数样式。例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同一方法内的几个参数类型必须不一样,例如可以是fun(int, float), 但是不能为fun(int, int)); 
2、不能通过访问权限、返回类型、抛出的异常进行重载; 
3、方法的异常类型和数目不会对重载造成影响; 
4、对于继承来说,如果某一方法在父类中是访问权限是priavte,那么就不能在子类对其进行重载,如果定义的话,也只是定义了一个新方法,而不会达到重载的效果

class A {
protected int method1(int a, int b) { return 0; }
}
public class B extends A{ 
public int method1(int a, int b) { return 0; } //正确,重写父类方法,可以扩大访问权限
//private int method1(int a, int b) { return 0; } //错误,重写父类方法,不能降低了访问权限
//private long method1(int a, int b) { return 0; } //错误,重写父类方法,不能改变返回值类型
public short method1(int a, long b) { return 0; }//正确,重载自身的方法,可以有不同的访问权限和返回值类型
}



Java中多态性的实现
面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。
多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式。(发送消息就是函数调用)
实现多态的技术称为:动态绑定(dynamic binding),是指在执行期间判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。
多态的作用:消除类型之间的耦合关系。
现实中,关于多态的例子不胜枚举。比方说按下 F1 键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的

就是 Word 帮助;在 Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。





 






 

第二讲     内部类

一、概述

        将一个类定义在另一个类的里面,对里面那个类就称为内部类(内置类,嵌套类)。

        当描述事物时,事物的内部还有事物,该事物用内部类来描述。因为内部事物在使用外部事物的内容。如定义一个描述人的类,而手、心脏等都属于人,然它们又有自己的功能描述,这时可以在人这个描述类中,定义一个描述心脏的类,也就是内部类。

        编译时,如果代码中有内部类,生成的class文件中会含有这样的文件:Test$1.class。编译器将会把内部类翻译成用$(美元符号)分隔外部类名和内部类名的常规类文件。这是内部类的一种编译现象。

 

二、内部类的访问规则

        1内部类可以直接访问外部类中的成员,包括私有。

              之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式:  外部类名.this

        2外部类要访问内部类,必须建立内部类对象。

 

三、访问格式

1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。可以直接建立内部类对象。

        格式:

                 外部类名.内部类名  变量名 =外部类对象.内部类对象;

        如:

        Outer.Inner in =new Outer().new Inner();

当内部类在外部类中的成员位置上时,可以被成员修饰符所修饰。比如:

        private:将内部类在外部类中进行封装。 

        static:内部类就局部static的特性。但是当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。

在外部其他类中,直接访问static内部类的非静态成员的格式为:

        new 外部类名.内部类名().方法名();

        如:new  Outer.Inner().function();

在外部其他类中,直接访问static内部类的静态成员格式为:

        外部类名.内部类名.方法名();

        如:Outer.Inner.function();

注意:

        1)当内部类中定义了静态成员时,该内部类必须是static的。

        2)当外部类中的静态方法访问内部类时,内部类也必须是static的。

        3)在实际应用中,内部类通常被定义为private,而很少定义为public

2、内部类定义在局部

        内部类定义在外部类中的某个方法中,创建了这个类型的对象时,且仅使用了一次,那么可在这个方法中定义局部类。

        1)不可以被成员修饰符修饰。如publicprivatestatic等修饰符修饰。它的作用域被限定在了声明这个局部类的代码块中

        2)可以直接访问外部类中的成员,因为还持有外部类中的引用。


注意:内部类不可以访问它所在的局部中非最终变量。只能访问被final修饰的局部变量。

原因:
           当方法被调用运行完毕之后,局部变量就已消亡了。但内部类对象可能还存在,
           直到没有被引用时才会消亡。此时就会出现一种情况,就是内部类要访问一个不存在的局部变量。



四、匿名内部类

        1、匿名内部类其实就是内部类的简写格式。

        2、定义匿名内部类的前提:

              内部类必须是继承一个类或者实现接口。

              特殊情况:因为所以的类都有一个父类Object,所以在定义时也可以用Object

        3、匿名内部类的格式:  new父类或者接口(){定义子类的内容}

        4、其实匿名内部类就是一个匿名子类对象。可以理解为带内容的对象。

        5匿名内部类中定义的方法最好不要超过3个。

匿名内部类的利与弊:

        好处:简化书写

        弊端:   1、不能直接调用自己的特有方法、

                     2不能做强转动作。

                     3如果继承的父类或接口中有很多方法时,使用匿名内部类阅读性会非常差,且调用会很麻烦。所以匿名内部类中定义的方法有一般不超过3






第三讲    异常


 先看一下一个简单的异常例子:

public class ExceptionTest
{
      public static void main(String[] args)
      {
             int a = 3;
             int b = 0;
             int c = a / b;          
             System.out.println(c);
      }
}

编译通过,执行时结果:

  Exception in thread "main" java.lang.ArithmeticException: / by zero

     at com.learnjava.exception.ExceptionTest.main(ExceptionTest.java:9)

  因为除数为0,所以引发了算数异常。


 

三、异常有两种:

        1、编译时被检测异常

              该异常在编译时,如果没有处理(没有抛也没有try),编译失败。该异常被标识,代表着可以被处理。

         2、运行时异常(编译时不检测)

               在编译时,不需要处理,编译器不检查。该异常的发生,建议不处理,让程序停止。需要对代码进行修正。如:RuntimeException以及其子类。

 


有三个结合格式:

        atry  catch 

        btry  finally

        ctry  catch   finally


注意:

        1finally中定义的通常是关闭资源代码。因为资源必须释放

        2)如果在一个功能中,定义了一些必须要执行的代码,可以用try{}finally{}的方式,将一定执行的代码放在finally代码块中。

        3finally只有一种情况不会执行。当执行到System.exit(0);fianlly不会执行。



2throwthrows的用法

        throw定义在函数内,用于抛出异常对象。

        throws定义在函数上,用于抛出异常类,可以抛出多个用逗号隔开。

        当函数内容有throw抛出异常对象,并未进行try处理。必须要在函数上声明,否则编译失败。

        注意:RuntimeException除外。也就说,函数内如果抛出的RuntimeExcpetion异常,函数上可以不用声明。



特殊之处:

        Exception中有一个特殊的子类异常RuntimeException 运行时异常。

                1 如果在函数内抛出该异常,函数上可以不用声明,编译一样通过。

                2如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过。

        之所以不用在函数上声明,是因为不需要让调用者处理。当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,对代码进行修正。

         如果函数声明了异常,调用者需要进行处理。处理方法可以throws可以try


将异常捕获

public class ExceptionTest2
{
    public void method() throws Exception // 将异常抛出,由调用这个方法的方法去处理这个异常,如果main方法也将异常抛出,则交给Java虚拟机来处理
    {
        System.out.println("Hello World");

        // 抛出异常
        throw new Exception();
    }

    public static void main(String[] args)
    {
        ExceptionTest2 test = new ExceptionTest2();

        try
        {
            test.method();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally
        {
            System.out.println("Welcome");
        }


    }

}

将异常抛出

public class ExceptionTest2
{
    public void method() throws Exception // 将异常抛出,由调用这个方法的方法去处理这个异常,如果main方法也将异常抛出,则交给Java虚拟机来处理
    {
        System.out.println("Hello World");

        // 抛出异常
        throw new Exception();
    }

    public static void main(String[] args) throws Exception // main方法选择将异常继续抛出
    {
        ExceptionTest2 test = new ExceptionTest2();

        test.method(); // main方法需要对异常进行处理

        // 执行结果:
        // Hello World
        // Exception in thread "main" java.lang.Exception
        // at com.learnjava.exception.ExceptionTest2.method(ExceptionTest2.java:10)
        // at com.learnjava.exception.ExceptionTest2.main(ExceptionTest2.java:17)
    }

}




对捕获到的异常对象进行常见方法操作:

        String getMessage();//获取异常的信息。返回字符串。

        toString();//获取异常类名和异常信息,返回字符串。

        printStackTrace();//获取异常类名和异常信息,以及异常出现在程序中的位置.返回值void.

                                //其实JVM默认的异常处理机制,就是在调用printStackTrace方法,打印异常的堆栈的跟踪信息。

        printStackTrace(PrintStream s)//通常用该方法将异常内容保存在日志文件中,以便查阅。

 

五、自定义异常

        

所谓自定义异常,通常就是定义一个类,去继承Exception类或者它的子类。因为异常必须直接或者间接地继承自Exception类。

  通常情况下,会直接继承自Exception类,一般不会继承某个运行时的异常类。

  自定义异常可以用于处理用户登录错误,用户输入错误提示等。

  自定义异常的例子:

  自定义一个异常类型: 

public class MyException extends Exception
{
    public MyException()
    {
        super();
    }    
    public MyException(String message)
    {
        super(message);
    }
}
一种异常处理方式:
public class MyException extends Exception
{
    public MyException()
    {
        super();
    }    
    public MyException(String message)
    {
        super(message);
    }
}



自定义异常时:如果该异常的发生,无法再继续进行运算,就让自定义异常继承RuntimeException

注:自定义异常:

                必须是自定义类有继承关系,通常继承Exception

         继承Exception原因:

                 异常体系有一个特点:因为异常类和异常对象都被抛出。他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。

                 只有这个体系中的类和对象才可以被throwsthrow操作。


 


0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:2751次
    • 积分:170
    • 等级:
    • 排名:千里之外
    • 原创:15篇
    • 转载:0篇
    • 译文:0篇
    • 评论:0条