黑马程序员——Java 面向对象(下)
来源:互联网 发布:java 就业培训机构 编辑:程序博客网 时间:2024/05/31 20:51
-----------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)不可以被成员修饰符修饰。如public、private、static等修饰符修饰。它的作用域被限定在了声明这个局部类的代码块中
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以及其子类。
有三个结合格式:
a、try catch
b、try finally
c、try catch finally
注意:
1)finally中定义的通常是关闭资源代码。因为资源必须释放。
2)如果在一个功能中,定义了一些必须要执行的代码,可以用try{}finally{}的方式,将一定执行的代码放在finally代码块中。
3)finally只有一种情况不会执行。当执行到System.exit(0);fianlly不会执行。
2、throw和throws的用法
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这个体系中独有特点。
只有这个体系中的类和对象才可以被throws和throw操作。
- 黑马程序员——Java 面向对象(下)
- 黑马程序员——Java 面向对象(下)
- 黑马程序员 — 面向对象(下)
- 黑马程序员—面向对象(下)
- 黑马程序员——Java基础->面向对象(下)
- 黑马程序员--Java面向对象——(其他对象)
- 黑马程序员——java面向对象
- 黑马程序员——java:面向对象
- 黑马程序员——Java面向对象
- 黑马程序员——java-面向对象
- 黑马程序员——JAVA面向对象
- 黑马程序员——JAVA面向对象
- 黑马程序员——java面向对象
- 黑马程序员——Java面向对象
- 黑马程序员—java面向对象一
- 黑马程序员—java面向对象二
- 黑马程序员 java基础<—>--->面向对象
- 黑马程序员—JAVA面向对象
- linux环境变量的临时设置,永久设置和其他。
- c++primer要点-表达式
- CodeForces 3DLeast Cost Bracket Sequence优先队列
- Android 分包机制
- 【设计模式】动态代理Proxy_02
- 黑马程序员——Java 面向对象(下)
- 根据浏览器导入不同css文件
- GRE写作必备句型
- 黑马程序员——Java基础---面向对象总结
- 广工anyview数据结构-03(乱码不贴)
- Bochs 最新版安装(debian) 及调试 hello world OS 详解
- CheckBox的单选框实现
- NSCharacterSet 最常用的用法
- mysql同步中索引问题