1、面向对象的编程思想
学习java,首先要了解的就是什么是面向对象的思想,那什么是面向对象呢? 面向对象(Object Oriented)是一种思想,是基于面向过程而言的,那面向过程又是什么呢。
面向过程(Procedure Oriented)是一种基本的方法,考虑的是实际的实现,从上往下步步求精。面向过程最重要的就是模块化的思想方法,例如我们每天上班来说,可以
将过程粗略的比拟为:(1)起床 (2)穿衣 (3)洗漱 (4)去公司。即分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候依次调用就可以。
相对面向过程,面向对象就是把事物对象化,赋予这个对象属性与行为,例如将车看成是一个对象,由对象引发事件,这个对象有自己的属性,像轮胎,颜色等;也有自
己的方法,像启动,行驶等,方法就是汽车的行为,而不是汽车的每个事件。
2、走入多态的世界
(1)多态分为两种:
a、编译时多态:方法的重载;
b、运行时多态:Java运行时系统根据调用该方法的实例的类型来决定选择调用哪个方法则被称为运行时多态(平时我们所说的多态多指运行时多态)。
(2)运行时多态
a、面向对象的三大特性:封装、继承、多态。一般来看,封装和继承就是为多态而准备的。
b、多态的定义:指允许不同类的对象对同一消息做出响应。即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息即为函数调用)。
c、多态的作用:消除类型之间的耦合关系。
d、同一个事件发生在不同的对象上会产生不同的结果。
e、多态存在的三个必要条件:(a)要有继承;(b)要有重写;(c)父类引用指向子类对象。
(3)多态的好处:
可替换性:多态对已存在代码具有可替换性。例如多态对圆类工作,对其他任何圆形几何体也同样工作。
可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性,继承性以及其他特性的运行和操作。
接口性:多态是超类通过方法签名,向子类提供了一个共同接口,由子类来完善或者覆盖它而实现的。
灵活性:在应用中体现了灵活多用的操作,提高了使用效率。
简化性:多态简化对应用软件的代码编写和修改过程,在处理大量对象的运算和操作时尤为明显。
代码理解:
运行时多态是在父类指向子类对象时产生的,一个父类的引用可以指向多种子类对象,对于同一个消息如何响应由被引用对象的类型来决定。
为什么要有重写,父类中的方法被重写后是如何调用的。举个栗子:
1 public class A{ 2 int ivar = 7; 3 void m1(){ 4 System.out.print("A's m1, "); 5 } 6 void m2(){ 7 System.out.print("A's m2, "); 8 } 9 void m3(){ 10 System.out.print("A's m3, "); 11 } 12 } 13 public class B extends A{ 14 void m1(){ 15 System.out.print("B's m1, "); 16 } 17 } 18 public class C extends B{ 19 void m3(){ 20 System.out.print("C's m3, "+(ivar+6)); 21 } 22 } 23 public class Mixed2{ 24 public static void main(String [] args){ 25 A a = new A(); 26 B b = new B(); 27 C c = new C(); 28 A a2 =new C(); 29 a.m1(); 30 b.m2(); 31 c.m3(); 32 //a2.m1()........输出为B's m1, 33 //a2.m2()........输出为A's m2, 34 //a2.m3()........输出为C's m3, 13 35 } 36 }
输出是什么呢???
A's m1, A's m2,C's m3, 13
thinking!!!
当父类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在父类中定义过的,即被子类覆盖过的方法。
tips:子类重写父类的方法时,访问权限不能变低。
3、深入多态~接口与抽象类
首先来理解一下什么是抽象类,为什么要有抽象类?
假如很多人要买水果吃,吃的动作只有一个,但是有的人要用现金买,有的人用信用卡,有的人赊帐。要为每个人定义一个类,就要定义多个相同的吃的方法。如果定义一个抽象类,
在里面实现吃的方法,再做一个买的抽象方法。那每个人的类都从这个抽象类派生下来,只要实现买的方法即可,吃的方法就可以直接用父类的方法了。如果要改吃的方法就不用改多个,
只要改这个抽象类里的就行了。
假如有两个程序员,两个在两个程序里都要用到一种功能,比如要取一个对象名。甲自己做了一个方法叫getname,乙也作了一个方法叫qumingzi。如果两个人要去看对方的程序,那
么这个方法要读懂是不是要有一个过程?如果在公司里,有个抽象类,里面有个抽象方法叫getName,公司规定,凡遇到这样的问题就实现这个方法。那么这两个人要读对方的代码是不是
就容易了??
抽象类就是不能使用new方法进行实例化的类,即没有具体实例对象的类,抽象类有点类似“模板”的作用,目的是根据其格式来创建和修改新的类,对象不能由抽象类直接创建,只可以
通过抽象类派生出新的子类,再由其子类来创建对象,当一个类被声明为抽象类时,要在这个类前面加上修饰符abstract,在抽象类中的成员方法可以包括一般方法和抽象方法。
抽象方法:抽象方法就是以abstract修饰的方法,这种方法只声明返回的数据类型,方法名称和所需要的参数,没有方法体,也就是说抽象方法只需要声明而不需要事先,当一个方法为
抽象方法时,意味着这个方法必须被子类的方法所重写,否则其子类的该方法仍然是abstract的,而这个子类也必须是抽象的,即声明为abstract。
抽象类中不一定包含抽象方法,但是包含抽象方法的一定要被声明为抽象类,抽象类本身不具备实际的功能,只能用于派生其子类,抽象类中可以包含构造方法,但是构造方法不能被
声明为抽象,抽象类不能用final来修饰,即一个类不能既是最终类又是抽象类,abstract不能与private,static,final,native并列修饰同一个方法。
抽象类的定义: public abstract class B{...}
抽象方法的定义:当类中的方法在声明的时候加上abstract关键字( public abstract void eat() ;没有方法体,直接以分号结束)。
接口的思想在于它可以增加很多类都需要实现的功能,使用相同的接口类不一定有继承关系,同一个类也可以实现多个接口,接口只关心功能,并不关心功能的具体实现。
接口的定义: public interface Pet{...}
接口的实现: public class Dog extends Canine implements Pet{...}
接口和抽象类的区别:
Java提供和支持创建抽象类和接口。它们的实现有共同点,不同点在于:
(1)接口中所有的方法隐含的都是抽象的。而抽象类则可以同时包含抽象和非抽象的方法。
(2)类可以实现很多个接口,但是只能继承一个抽象类。
(3)类如果要实现一个接口,它必须要实现接口声明的所有方法。但是类不可以实现抽象类声明的所有方法,当然,在这种情况下,类也必须得声明成是抽象的。
(4)抽象类可以在不提供接口方法实现的情况下实现接口。
(5)Java接口中声明的变量默认都是final的。抽象类可以包含非final的变量。
(6)Java接口中的成员函数默认是public的。抽象类的成员函数可以是private,protected或者public。
(7)接口是绝对抽象的,不可以被实例化。抽象类也不可以被实例化,但是,如果它包含main方法的话是可以被调用的。
小栗子:
1 interface Nose{ 2 public int iMethod(); 3 } 4 abstract class Picasso implements Nose{ 5 public int iMethod(){ 6 return 7; 7 } 8 } 9 class Clowns extends Picasso{ 10 public int iMethod(){ 11 return 5; 12 } 13 } 14 public class Of76 extends Clowns{ 15 public static void main(String[] args) { 16 Nose []i=new Nose[3]; 17 i[0] = new Acts(); 18 i[1] = new Clowns(); 19 i[2] = new Of76(); 20 for (int x = 0 ; x < 3 ; x++ ) { 21 System.out.println(i[x].iMethod()+" "+i[x].getClass()); 22 } 23 } 24 } 25 /*输出为:5 class Acts 26 7 class Clowns 27 7 class Of76*/
4、继承
super关键字可以取用父类.................
子类可以继承父类的成员,包括实例变量和方法.............
父类可以通过存取权限来决定子类是否能够继承某些特定的成员.............
private default protected public 从左往右,限制程度越来越小.........
public类型的成员会被继承,private的成员不会被继承...........
子类是extends父类出来的..........
子类会继承父类所有public类型的实例变量和方法,但不会继承父类所有private类型的变量和方法.............
继承下来的方法可以被覆盖掉,但实例变量不能被覆盖掉...............
当某个方法在子类被覆盖过,调用这个方法时会调用到覆盖过的版本............
5、异常
5.1异常(程序出现错误的情况)
(1)异常的体系
Throwable
|--Error 严重问题,我们不处理(如:内存溢出),要修改程序。
|--Exception (Java中的异常被分为两大类:编译时期异常和运行时期异常。)
|--RuntimeException 运行期异常,我们需要修正代码(代码不严谨,但编译会通过)
|--非RuntimeException(及其子类) 编译期异常,必须处理的,否则程序编译不通过
编译时异常和运行时异常的区别:
编译期异常:Java程序必须显示处理,否则程序就会发生错误,无法通过编译
运行期异常:无需显示处理,也可以和编译时异常一样处理
(2)异常的处理:
A:JVM的默认处理
把异常的名称,错误原因及异常出现的位置等信息输出在了控制台,程序停止执行(异常后面不执行)
B:自己处理(自己编写处理代码,后面的程序可以继续执行)
(1)try...catch...finally...格式:
A.基本格式
try {
//可能出现问题的代码;
}catch(异常名 变量) {
//针对问题的处理;
}finally {
//必须执行的代码(释放资源);
}
B.变形格式(try...catch...后面代码正常执行)
try {
可能出现问题的代码;
}catch(异常名 变量) {
针对问题的处理;
}
注意:
A:try里面的代码越少越好
B:catch里面必须有内容,哪怕是给出一个简单的提示
C:try是检测异常,catch是用来捕获异常的,finally是用来结束资源的
(2)针对多个异常的处理
1)每一个异常写一个try...catch (每个异常都会处理)
2)写一个try(在try内写所有产生异常的代码),多个catch (处理多个异常中第一个异常)
try{
...
}catch(异常类名 变量名) {
...
}
catch(异常类名 变量名) {
...
}
...
注意事项:
1:能明确的异常尽量明确,不要用大范围的异常来处理。
2:平级关系的异常 catch 捕获顺序随意,如果出现子父异常,父异常必须在子异常后面(即:大范围异常在后)
3:一旦try里面出现异常,jvm会帮我们生成一个异常对象,并在这里把异常对象给抛出去,然后和catch里面的异常进行匹配,一旦有匹配的,就执行catch里面的处理,然后结束
try...catch(即一旦出现异常ry里面的后续代码不再执行)。继续执行try...catch...后面的语句。
(3)JDK7出现了一个新的异常处理方案:(多个异常间必须是平级关系)实际开发中,好多时候可能就是针对同类型的问题,给出同一个处理
try{
//可能出现问题的代码;
}catch(异常名1 | 异常名2 | ... 变量名 ) {
//针对问题的处理(各异常处理方式是一致的);
}
(4)throws抛出异常
把自己处理不了的异常,在方法上声明。
格式:
throws 异常类名
注意:1)这个格式必须跟在方法的小括号后面; 2)尽量不要在main方法上抛出异常。
小结:
编译期异常抛出,将来调用者必须处理。
运行期异常抛出,将来调用可以不用处理。
(5)throw抛出异常
如果出现了异常情况,我们可以把该异常抛出,这个时候的抛出的应该是异常的对象。
(3)Throwable类的成员方法:
public String getMessage():返回此异常的详细消息字符串。
public String getLocalizedMessage():返回此异常的本地化描述。对于不重写此方法的子类,默认实现返回与 getMessage() 相同的结果。
public String toString():返回此异常的简短描述(异常类名和异常信息)。
public void printStackTrace():把异常类名和异常信息,以及异常在程序中出现的位置输出在控制台
public void printStackTrace(PrintStream s):把异常类名和异常信息,以及异常在程序中出现的位置输出在指定文件中。
(4)自定义异常类(用来创建异常对象并抛出)
要定义异常类,就必须继承自Exception或者RuntimeException,并且在自定义类中提供无参构造和一个带参构造即可。
(5)异常注意事项
A.子类重写父类方法时,子类的重写方法必须抛出与父类相同的异常或父类异常的子类。
B.如果父类方法抛出了多个异常,子类重写父类方法时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常(即,子的重写方法异常必须比父少或者小)
C.如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws