java基础---->面向对象3
一、继承1、继承的限制
1、 子类可以继承父类的全部操作(属性、方法),但是对于所有的公共操作是可以直接继承的,而所有的私有操作是无法直接进程的,而是通过其他的方式间接访问。
2、 一个子类只能继承一个父类,属于单继承
3、 在Java中允许多层继承。
2、子类对象的实例化所以按照正常的思维来讲,肯定是先有父类产生再有子类产生,所以在子类对象实例化的时候实际上都会默认去调用父类中的无参构造方法。
class Person { private String name ; private int age ; public Person(){ System.out.println("** 父类的无参构造!") ; } public Person(String name,int age){ }};class Student extends Person { // 现在没有编写任何代码 private String school ; // 扩充的属性 public Student(){ System.out.println("** 子类的无参构造!") ; }};public class ExtDemo06 { public static void main(String args[]){ Student stu = new Student() ; }};
以上的代码的运行效果符合于现实生活中的场景,但是对于子类构造方法而言,实际上在构造方法中隐含了一条super语句:
public Student(){ super() ; // 调用父类中的无参构造 System.out.println("** 子类的无参构造!") ; }
既然在子类中可以通过super关键字调用父类中的无参构造,那么就一定可以通过super调用父类中的有参构造。
也就是说,不管子类如何操作,肯定都会调用父类中的构造方法。
二、覆写在子类中定义了和父类完全一样的方法或者是定义了一样的属性,那么此时实际上就发生了覆写操作。
1、方法的覆写所谓方法的覆写就是指一个子类中定义了一个与父类完全一样的方法名称,包括返回值类型、参数的类型及个数都是完全一样的,但是需要注意的是,被覆写的方法不能拥有比父类更严格的访问控制权限。
class A { public void print(){ // 定义方法 System.out.println("hello") ; }};class B extends A { public void print(){ System.out.println("world") ; }};public class OverrideDemo01 { public static void main(String args[]){ B b = new B() ; b.print() ; }};
在子类中一旦方法被覆写之后,实际上最终调用的方法就是被覆写过的方法,但是,如果此时在子类中的方法的访问权限已经降低的话,则编译的时候将出现错误:
OverrideDemo01.java:7: print() in B cannot override print() in A; attempting to assign weaker access privileges; was public
void print(){
^
一定要记住,方法名称、返回值了性、参数列表完全一样就称为覆写。
问题?如果现在父类中有一个方法是private声明,子类将其方法定义成了default访问权限,其他不变,是否叫覆写呢?
class A { public void print(){ // 定义方法 this.getInfo() ; } private void getInfo(){ System.out.println("A --> getInfo()") ; }};class B extends A { void getInfo(){ System.out.println("B --> getInfo()") ; }};public class OverrideDemo02 { public static void main(String args[]){ B b = new B() ; b.print() ; //A --> getInfo() }};
记住使用private声明的方法子类是无法覆写的,虽然语法编译上不会产生任何的问题,但是子类中被“覆写”过的方法永远无法找到,而且这种代码在实际中没有任何的意义。
如果现在子类中需要调用父类中已经被子类覆写过的方法,可以通过super关键字完成。
super就是直接由子类找到父类中指定的方法,而如果使用的是this的话,则会先从本类查找,如果查找到了就直接使用,查找不到,则再去父类中查找,super是直接从父类中查找。
2、重载及覆写的区别No.
区别点
重载
覆写
1
定义
方法名称相同,参数的类型或个数不同
方法名称、参数的类型或个数、返回值相同
2
权限
没有权限要求
被覆写的方法不能拥有比父类更严格的权限
3
范围
发生在一个类之中
发生在继承关系中
4
单词
OverLoading
Override
三、this与super的区别No.
区别点
this
super
1
使用
调用本类中的属性或方法
从子类调用父类中的属性或方法
2
构造
可以调用本类构造,且有一个构造要作为出口
从子类调用父类的构造方法,不管子类如何安排最终一定会去调用,默认调用的是父类中的无参构造方法
3
要求
调用构造的时候一定要放在构造方法首行
放在子类构造方法首行
使用super和this调用构造方法的语句是不可能同时出现的
4
特殊
表示当前对象
无此概念
四、final关键字
在Java中可以使用final关键字定义类、方法、属性:
使用final关键字定义的类不能有子类
使用final声明的方法不能被子类所覆写
使用final声明的变量即成为常量,常量必须在声明时给出具体的内容。
在声明一个常量的时候所有的单词的字母都必须采用大写的形式出现,
五、单例设计class Singleton { private static final Singleton instance = new Singleton() ; // 在内部准备好一个对象 public static Singleton getInstance(){ // 将instance传递到外部去 return instance ; } private Singleton(){} public void print(){ System.out.println("Hello World!!!") ; }};public class Test{ public static void main(String args[]){ Singleton s1 = Singleton.getInstance() ; Singleton s2 = Singleton.getInstance() ; Singleton s3 = Singleton.getInstance() ; s1.print() ; s2.print() ; s3.print() ; }};
此时,不管外部如何变化,Singleton类中永远只会有一个实例化对象,此种代码实现的根本原理就是在于将一个类的构造方法关闭了。
当一个类中只能产生一个实例化对象的时候,就需要将构造方法封闭,封闭之后的操作通过一个静态方法取得本类的实例化对象,这种代码的概念非常重要,而且代码的结构必须清楚。
编写Singleton类的话,就按照此种代码完整写出即可。
如果要想继续划分的,实际上单例设计,还分成两种类型:
懒汉式:当第一次使用本类的对象时,在进行对象的实例化操作。
饿汉式:一个单例类中不管是否使用,都始终维护一个实例化对象。
class Singleton { private static Singleton instance = null ; public static Singleton getInstance(){ // 将instance传递到外部去 if(instance == null){ instance = new Singleton() ; } return instance ; } private Singleton(){} public void print(){ System.out.println("Hello World!!!") ; }};public class Test{ public static void main(String args[]){ Singleton s1 = Singleton.getInstance() ; Singleton s2 = Singleton.getInstance() ; Singleton s3 = Singleton.getInstance() ; s1.print() ; s2.print() ; s3.print() ; }};
既然程序中可以存在单例设计,那么就可以存在多例设计。
class Color { private static final Color RED = new Color("红色") ; private static final Color GREEN = new Color("绿色") ; private static final Color BLUE = new Color("蓝色") ; private String name ; public static Color getInstance(int ch){ // 将instance传递到外部去 if(ch==0){ return RED ; } else if(ch==1){ return GREEN ; } else if(ch==2){ return BLUE ; } else { return null ; } } private Color(String name){ this.name = name ; } public void print(){ System.out.println("当前颜色:" + this.name) ; }};public class Test{ public static void main(String args[]){ Color s1 = Color.getInstance(0) ; Color s2 = Color.getInstance(1) ; Color s3 = Color.getInstance(2) ; s1.print() ; s2.print() ; s3.print() ; }};
六、抽象类
抽象类的定义比较简单,包含一个抽象方法的类就是抽象类,抽象类必须使用abstract关键字进行声明。
抽象方法:只声明而未定义方法体的方法称为抽象方法,抽象方法也必须使用abstract关键字声明。
范例:定义一个抽象类
abstract class Demo { // 抽象类 public void print(){ System.out.println("Hello World!!!") ; } public abstract void fun() ; // 抽象方法};
由于Demo是一个抽象类,所以无法进行实例化,所以抽象类使用有以下原则:
1、 抽象类不能直接实例化。
2、 抽象类必须有子类,子类(如果不是抽象类)的话,则必须覆写抽象类中的全部抽象方法。
3、 如果一个抽象类中没有任何一个抽象方法,依然是抽象类。
2、 抽象类中能有构造方法吗?
可以存在,而且依然符合于子类对象的实例化过程的要求。
abstract class Demo { // 抽象类 public Demo(){ System.out.println("抽象类中的构造方法!") ; } public void print(){ System.out.println("Hello World!!!") ; } public abstract void fun() ; // 抽象方法};class DemoImpl extends Demo { public DemoImpl(){ super() ; System.out.println("子类中的构造方法!") ; } public void fun(){}};public class AbsDemo03 { public static void main(String args[]){ DemoImpl di = new DemoImpl() ; di.print() ; }};
抽象类和普通类相比,只是增加了抽象abstract class的声明,和增加了抽象方法而已。
七、接口当一个类中全部是由抽象方法和全局常量组成的时候,那么就可以将这个类定义成一个接口了,接口使用interface关键字声明。
范例:定义接口
interface Demo{ // 接口 public static final String INFO = "hello world" ; public abstract void print() ; public abstract void fun() ;}
一个接口定义完成之后,实际上与抽象类的使用原则是一样的:
1、 接口必须有子类,子类(如果不是抽象类)则必须覆写接口中的全部抽象方法;
2、 接口是不能直接进行对象的实例化操作。
3、 一个子类可以同时继承(实现)多个接口
但是,一个子类一般而言如果要实现接口又要继承类的话,则必须先继承抽象类之后再实现接口.即extends要卸载implements的前面。
既然接口中的全部组成都是抽象方法和全局常量的话,那么以下的两种定义接口的形式是完全一样的:
interface Demo{ //接口
public static final String INFO = "hello world" ;
public abstractvoid print() ;
}
interface Demo{ //接口
String INFO = "hello world" ;
void print() ;
}
所有的修饰符在接口中是否添加本身是没有任何意义的,而且接口中的方法全部都属于公共的方法操作(public)。
对于接口而言本身还有一个很大的特点:一个接口可以同时通过extends关键字继承多个接口。
interface A{ public void printA() ;}interface B{ public void printB() ;}interface C extends A,B{ public void printC() ;}class Demo implements C { public void printA(){} public void printB(){} public void printC(){}};
八、对象多态性
在面向对象中多态性实际上是面向对象里的一个最大的最有用的特点,对于多态性在java中有两种体现:
1、 方法的重载及覆写
2、 对象多态性:指的是父类对象和子类对象之间的转型操作
向上转型(子类à父类):父类名称父类对象 =子类实例 ; 自动完成
向下转型(父类à子类):子类名称子类对象 =(子类名称)父类实例 ; 强制完成
所谓的向上转型,实际上指的就是一个子类变为父类接收,但是调用的方法肯定是被子类所覆写过的操作。
class A { public void print(){ System.out.println("A --> public void print(){}") ; } public void fun(){ this.print() ; }};class B extends A { public void print(){ System.out.println("B --> public void print(){}") ; }};public class PolDemo01 { public static void main(String args[]){ A a = new B() ; // 子类对象变为父类对象 a.fun() ; // B --> public void print(){} }};
正确的向下转型
public class PolDemo02 { public static void main(String args[]){ A a = new B() ; // 子类对象变为父类对象 B b = (B) a ; // 父类对象变为子类对象 b.fun() ; }}public class PolDemo03 { public static void main(String args[]){ A a = new A() ; // 父类对象实例化 B b = (B) a ; // 父类对象变为子类对象 b.fun() ; }};
以上是错误的向下转型:程序执行的时候将出现以下的错误:发生向下转型之前,必须先发生向上转型
Exception in thread "main" java.lang.ClassCastException: A cannot be cast to B
表示的是一个类转换异常,主要的功能是由于两个类之间没有任何的关系所发生的转换。
在进行向下转型之前必须首先发生向上转型的关系,建立关系。
但是,在对象多态性中也必须注意一点,虽然可以发生向上转型的关系,但是也要考虑到一点,一旦发生了向上转型后,子类中自己的定义的操作是无法通过父类对象找到的。
class A {public void print(){System.out.println("A --> public void print(){}") ;}public void fun(){this.print() ;}};class B extends A {public void print(){System.out.println("B --> public void print(){}") ;}public void printB(){System.out.println("Hello B") ;}};public class PolDemo04 {public static void main(String args[]){A a = new B() ;// 父类对象实例化// a.printB() ;// 找不到 错误的 B b = (B) a ;// 向下转型b.printB() ;}};
九、instanceof关键字
通过instanceof关键字可以判断某一个对象是否是某一个类的实例。
class A {};class B extends A {};public class InstanceDemo { public static void main(String args[]){ A a = new A() ;A a1=new B(); System.out.println(a instanceof A) ;//true System.out.println(a instanceof B) ;//falseSystem.out.println(a1 instanceof A) ;//true System.out.println(a1 instanceof B) ;//true }};
所以,以后在进行向下转型操作之前,一定要先使用instanceof关键字进行验证,验证通过了,才可以放心安全的执行向下转型的操作。
public boolean equals(Object obj){ if(this == obj){ return true ; } if(!(obj instanceof Person)){ return false ; } Person per = (Person) obj ; if(this.name.equals(per.name) && this.age==per.age){ return true ; } else { return false ; } }
2、接收引用
对于Java的数据类型来讲,分为基本数据类型和引用数据类型,使用Object不光可以接收类的对象,只要是引用数据类型的对象都可以接收(数组、类、接口)。
int data[] = {1,2,3,4,5,6,7} ; Object obj = data ;