一、多态
定义:某一类事物存在的多种体现形态。例如,人的体现:男人、女人。
实体不能改变类型,内部封装的数据会被破坏。能改变的是栈中的数据,但不能改变堆中的数据。当父类引用指向了子类的对象时,该引用可以被提升,也可以被强制转换。多态都是子类的对象的指向在变化。
instanceof 判断对象是否属于类。使用:一是子类型有限;二是确定属于哪种子类型,确定调用的方法。
可以指挥一批对象执行方法,找到了对象的共同所属类型。建立父类后,在建立相应的工具类,在主函数中直接调用工具类即可。对类型进行抽取导致多态的产生,操作同一个大类型,对大类型中的所有子类型都可以操作。
abstract class Animal{
public abstract void eat();
}
class Cat extends Animal{
public void eat(){
System.out.println("吃鱼");
}
public void catchMouse(){
System.out.println("抓老鼠");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("吃骨头");
}
public void kanJia(){
System.out.println("看家");
}
}
class Pig extends Animal{
public void eat(){
System.out.println("吃饲料");
}
public void gongDi(){
System.out.println("拱地");
}
}
public class Demo{
public static void main(String[] args){
/*老方式
Cat c = new Cat();
c.eat();
Dog d = new Dog();
d.eat();
function(c);
function(d);
function(new Cat());
function(new Dog());
*/
//多态
Animal a = new Cat(); //类型提升,向上转型,子类向父类转
a.eat();
//如果想要调用猫的特有方法时,如何操作?
//强制将父类的引用,转成子类类型,向下转型
Cat c = (Cat)a; //既能向上转,也能向下转,强制将父类的引用,转成子类类型,向下转型,前提是, 创建时,他是引用的是他的子类。我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被转换
//多态自始至终都是子类对象在做着变化
c.catchMouse();
// Animal a = new Animal();
// Cat c = (Cat)a;//千万不要出现这样的操作,就是将父类对象转成子类类型。
//我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换
function(new Cat());
function(new Dog());
function(new Pig());
}
/*
public static void function(Cat c){
c.eat();
}
public static void function(Dog d){
d.eat();
}
public static void function(Pig d){
d.eat();
}
*/
//多态应用
public static void function(Animal a){
a.eat();
if(a instanceof Cat){ // instanceof 判断 该对象 是哪个类的 对象
Cat c = (Cat)a;
c.catchMouse();
}else if(a instanceof Dog){
}
}
}
在多态中(Fu f = new Zi();)非静态成员函数的特点:
编译时期:参阅引用变量所属的类中(父类)是否有调用的方法,如果有,编译通过;如果没有,编译失败。
运行时期:参阅对象所属的类中(子类)是否有调用的方法。对象在调用方法。找的是方法区中的非静态区,参考对象。相当于和this绑定,进而和对象绑定,即“动态绑定”。
简单总结:成员函数在多态调用时,编译看左边,运行看右边。相当于过滤了两遍。此情况最多见,因为有覆盖操作。
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 Demo{
public static void main(String[] args){
Fu f = new Zi();
// z.method1(); zi-1
// z.method2(); fu-2
// z.method3(); 错误
// Zi z = new Zi();
// z.method1(); zi-1
// z.method2(); fu-2
// z.method3(); zi-3
}
}
多态成员变量的特点:
无论编译还是运行,都参考左边(引用变量所属的类)。主要是针对同名变量的情况,一般很少发生。静态绑定。
多态中静态成员(变量和函数)的特点:
无论编译和运行都参考左边,即参考引用所属的类。静态函数随类加载,不所属于对象,所以参考引用型变量的类,相当于用父类直接调用。找的是方法区中的静态区,不参考对象。或者认为,静态方法一进内存,就已经被绑定到方法所属类上了,即“静态绑定”。没有覆盖,各走各的方法。
class Fu{
int num = 5;
static void method4(){
System.out.println("fu method_4");
}
}
class Zi extends Fu{
int num = 8;
static void method4(){
System.out.println("zi method_4");
}
}
public class Demo{
public static void main(String[] args){
Fu f = new Zi();
f.num; //为 5
Zi z = new Zi();
z.num; //为 8
f.method4(); //fu
z.method4(); //zi
}
}
接口型引用指向自己的子类对象。虽然不能产生对象,但可以产生引用,可以指向对象。类——》接口——》主程序,将相似的类中的方法抽象出来放在接口,使得类与主程序没有关系;只要类实现了接口,接口的引用就能指向类的对象;更改类的话,只要更改接口的引用,使其指向新类,即可调用新类的方法,接口和主程序无需变化。降低了主程序和某些类的耦合性,类似电源插排比直接接电源方便。
/*扩展差
class MainBoard{
public void run(){
System.out.println("MainBoard run");
}
public void useNetCard(NetCard c){
c.open();
c.close();
}
}
class NetCard{
public void open(){
System.out.println("NetCard open");
}
public void close(){
System.out.println("NetCard close");
}
}
public class Demo{
public static void main(String[] args){
MainBoard mb = new MainBoard();
mb.run();
mb.useNetCard(new NetCard());
}
}
*/
interface Pci{
public void open();
public void close();
}
class MainBoard{
public void run(){
System.out.println("MainBoard run");
}
public void usePci(Pci p){ //Pci p = new NetCard(); 接口型引用指向自己的子类对象
if(p!=null){
p.open();
p.close();
}
}
}
class NetCard implements Pci{
public void open(){
System.out.println("NetCard open");
}
public void close(){
System.out.println("NetCard close");
}
}
class SoundCard implements Pci{
public void open(){
System.out.println("SoundCard open");
}
public void close(){
System.out.println("SoundCard close");
}
}
public class Demo{
public static void main(String[] args){
MainBoard mb = new MainBoard();
mb.run();
mb.usePci(new NetCard());
mb.usePci(new SoundCard());
}
}
二、多态的扩展示例—— 数据库的操作
1、步骤
(1)、连接数据库
(2)、操作数据库
(1)、c:create
(2)、r:read
(3)、u:update
(4)、d:delete
(3)、关闭数据库
2、例子
1、类 Object 是类层次结构的跟雷。每个类都使用 Object 作为超类,所有对象(包括数组)都实现这个类的方法。
2、Object :是所有对象的直接或者间接父类,传说中的上帝
(1)、该类中定义的是所有对象都具备的功能
(2)、Object没有super
(3)、java认为所有对象都具备比较性
3、equals方法,指示其他某个对象是否与此对象“相等”。
(1)、实际是比较的对象引用的地址
4、Objedt 类中已经提供了对对象是否相同的比较方法
(1)、如果自定义类中也有比较相同的功能,没有必要重新定义
(2)、只要沿袭父类中的功能,建立自己特有比较内容即可,这就是覆盖
(3)、多态的时候,使用子类特有成员,要注意向下转型
5、例子
class DemoTest{
private int num;
DemoTest(int num){
this.num = num;
}
public boolean equals(Object obj){
if(obj instanceof DemoTest){
DemoTest d = (DemoTest)obj;
return this.num == d.num;
}
}
}
public class Demo{
public static void main(String[] args){
//UserInfoByJDBC ui = new UserInfoByJDBC();
DemoTest d1 = new DemoTest(1);
DemoTest d2 = new DemoTest(2);
System.out.println(d1.equals(d2));
}
}
四、toString
public String toString()返回该对象的字符串表示。通常,toString 方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object 类的 toString 方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“@”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于:
getClass().getName() + '@' + Integer.toHexString(hashCode())
返回:
该对象的字符串表示形式。
对于这些方法,在创建类的时候都要做覆盖操作,建立自身的各种方法。