-------android培训、java培训、期待与您交流-------
01面向对象(多态-概念)
定义:某一类事物的多种存在形态。
例:动物中猫,狗。
猫这个对象对应的类型是猫类型
猫 x = new 猫();
同时猫也是动物中的一种,也可以把猫成为动物
动物 y = new 猫();
动物是猫和狗具体事物中抽取出来的父类型。
父类型引用指向了子类对象。
02面向对象(多态-扩展性)
1.多态的体现
父类引用指向了自己的子类对象。
父类的引用也可以接收自己的子类对象。
Animal c = new Cat();
c.eat();
function(new Cat());
function(new Dog());
function(new pig());
public static void function(Animal a)//Animal a = new Cat();
{
a.eat();
}
2.多态的前提
必须是类与类之间有关系,要么继承,要么实现。
通常还有一个前提:存在覆盖。
3.多态的好处
多态的出现大大的提高程序的扩展性。
4.多态的弊端
提高了扩展性,但是只能使用父类的引用访问父类中的成员
03面向对象(多态-转型)
第二个问题:如何使用子类特有方法。
public static void main(String[] args)
{
Animal a = new Cat();//类型提升。 向上转型。把猫提升为了动物
byte b= 2; int x = b; // b会被提升为int类型。
a.eat();
}
如果想要调用猫的特有方法时,如何操作?
强制将父类的引用,转成子类类型。 向下转型
Cat c = (Cat)a; 强制转换
c.catchMouse();
千万不要出现这样的操作,就是将父类对象转成子类类型。
我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。
多态自始至终都是子类对象在做着变化。
Animal a = new Animal();
Cat c = (Cat)a;
毕姥爷 x = new 毕老师();
x.讲课();
毕老师 y = (毕老师)x;
y.看电影();
public static void function(Animal a)//Animal a = new Cat();
{
a.eat();
/*
if(a instanceof Animal) 判断时不要把父类写在上面,否则下面的就不用判断了!
{
System.out.println("haha");
}
else
*/
if(a instanceof Cat)
{
Cat c = (Cat)a;
c.catchMouse();
}
else if(a instanceof Dog)
{
Dog c = (Dog)a;
c.kanJia();
}
/*
instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)
*/
}
因为在后期如果再有其他子类类型出现(pig),还要在后面加else if语句进行判断,所以一般情况下不用
什么时候用instanceof:
子类类型是有限的, 人 要么男人要么女人
当你传的类型需要进行其他操作,比如说比较,必须得确定它到底是哪种子类型,我要调用它的特有方法来比较,这个时候会用instanceof来判断
instanceof 用来判断所属类型 判断完后就可以用这个所属类型中的特有方法
04面向对象(多态-示例)
/*
基础班学生:
学习,睡觉。
高级班学生:
学习,睡觉。
可以将这两类事物进行抽取。
*/
abstract class Student
{
public abstract void study();
public void sleep()
{
System.out.println("躺着睡");
}
}
class DoStudent
{
public void doSome(Student stu)
{
stu.study();
stu.sleep();
}
}
class BaseStudent extends Student
{
public void study()
{
System.out.println("base study");
}
public void sleep() // 将父类中的躺着睡覆写
{
System.out.println("坐着睡");
}
}
class AdvStudent extends Student
{
public void study()
{
System.out.println(" adv study");
}
}
class DuoTaiDemo3
{
public static void main(String[] args)
{
DoStudent ds = new DoStudent();
ds.doSome(new BaseStudent());
ds.doSome(new AdvStudent());
// BaseStudent bs = new BaseStudent(); //把这些功能进行封装进DoStudent类中
// bs.study();
// bs.sleep();
// AdvStudent as = new AdvStudent();
// as.study();
// as.sleep();
}
多态将对象调用这件事情变简单了,以前是指挥每一个对象做事情,现在是可以指挥一批对象做事情,是因为找到了这些对象的共同所属类型,只要将事物不断的向上抽象,总能找到共同点,找到后就可以统一操作很多对象了。
05面向对象(多态中成员的特点)
class Fu
{
static int num = 5;
void method1()
{
System.out.println("fu method_1");
}
void method2()
{
System.out.println("fu method_2");
}
static void method4()
{
System.out.println("fu method_4");
}
}
class Zi extends Fu
{
static int num = 8;
void method1()
{
System.out.println("zi method_1");
}
void method3()
{
System.out.println("zi method_3");
}
static void method4()
{
System.out.println("zi method_4");
}
}
class DuoTaiDemo4
{
public static void main(String[] args) //对上面的代码进行调用
{
// Fu f = new Zi();
//
// System.out.println(f.num); 面试 在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
//
// Zi z = new Zi();
// System.out.println(z.num);
结果为 5 8 第二个是子类的 第一个是父类引用指向子类对象为什么 还是运行父类呢
在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
//f.method1(); 为什么执行子。因为method1()方法存储在方法区的非静态区,在非静态区中有俩个引用:this super,而静态区中只有类名引用:fu zi this.method1()
当我们调用method1()时,f确实是指向对象,method1()被运行的时候,最终是被对象运行,对象在调用非静态方法时,访问的是对象中的数据,而静态方法它本身不访问对象特有数据,所以都可以只用类名调用,只看这个f引用型变量所属类中的成员:它找的是静态区中的方法,不参考右边的对象,
//f.method2();
//f.method3();
Fu f = new Zi();
System.out.println(f.num);
f.method4();
在多态中,静态成员函数的特点:
无论编译和运行,都参考左边
static 非静态
fu.method4() f.method1()
静态绑定 动态绑定 对象是谁就运行谁的 若写成Fu f = new Fu(); 就会去找fu类中的method1
当method4()方法一进内存,因为是静态方法,它就已经被绑定了,绑定在方法所属类当中,在调用时就已经存在fu.method4()
Zi z = new Zi();
z.method4();
/*
在多态中(父类有指向对象的时候)成员函数的特点: 非静态 有重写特性(运行时看子类)
在编译时期:参阅引用型变量所属的类中(fu类中)是否有调用的方法。如果有f.method1();,编译通过,如果没有编译失败。f.method3();
子类自己有,执行自己的,没有就执行父类,只有父类没有才会编译失败。
局部有变量,就访问局部的,没有就找成员变量;成员也没有,找父类,父类也没有,编译肯定失败。
在运行时期:参阅对象所属的类中(zi类中)是否有调用的方法。
简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
下面的几乎都是面试时才用到
在多态中,成员变量的特点:
无论编译和运行,都参考左边(引用型变量所属的类)。
在多态中,静态成员函数的特点: 静态只参考引用所属
无论编译和运行,都参考做左边。
父类引用指向子类对象对于静态方法对象调用时是不一样的:父类走父类,子类走子类
*/
// Zi z = new Zi();
// z.method1();
// z.method2();
// z.method3();
} 打印结果
zi method_1 因为 zi_1将fu_1覆盖掉了
fu method_2 因为 子类继承过来了
zi method_3 因为子类特有
}
Fu f = new Zi();
f.method1();
f.method2();
f.method3(); //method3(); 找不到 因为父类中没有这个方法 编译的时候对象还没有产生(new Zi) 所以说编译时只看那个f所属类型中有没有f.method3(),
//如果有就编译通过,如果没有就编译失败编译失败
Fu f = new Zi();
f.method1();
f.method2();
// 这样结果是 zi_1 fu_2
06面向对象(多态的主板示例)
/*
需求:
电脑运行实例,
电脑运行基于主板。
*/
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");
method();
}
}
class SoundCard implements PCI
{
public void open()
{
System.out.println("SoundCard open");
}
public void close()
{
System.out.println("SoundCard close");
}
}
/*
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");
}
}
*/
class DuoTaiDemo5
{
public static void main(String[] args)
{
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}
}
接口的出现增加了功能扩展,
多态的应用提高了程序的扩展性(接口型引用)
接口降低了耦合性,提高功能扩展性,提供了规则
07面向对象(多态的扩展示例)
/*
需求:数据库的操作。
数据是:用户信息。
1,连接数据库。JDBC Hibernate
2,操作数据库。
c create r read u update d delete
3,关闭数据库连接。
*/
interface UserInfoDao
{
public void add(User user);
public void delete(User user);
}
class UserInfoByJDBC implements UserInofDao
{
public void add(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
public void delete(User user)
{
1,JDBC连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}
class UserInfoByHibernate implements UserInfoDao
{
public void add(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句添加数据。;
3,关闭连接。
}
public void delete(User user)
{
1,Hibernate连接数据库。;
2,使用sql添加语句删除数据。;
3,关闭连接。
}
}
class DBOperate
{
public static void main(String[] args)
{
//UserInfoByJDBC ui = new UserInfoByJDBC();
// UserInfoByHibernate ui = new UserInfoByHibernate();
UserInfoDao ui = new UserInfoByHibernate();
ui.add(user);
ui.delete(user);
}
}
08面向对象(Object类-equals())
/*
Object:是所有对象的直接或者间接父类,传说中的上帝。
该类中定义的肯定是所有对象都具备的功能。
Object类中已经提供了对对象是否相同的比较方法。
如果自定义类中也有比较相同的功能,没有必要重新定义。
只要沿袭父类中的功能,建立自己特有比较内容即可。这就是覆盖。
*/
class Demo //extends Object
{
private int num;
Demo(int num)
{
this.num = num;
}
}
class Person
{
}
public boolean equals(Object obj)//Object obj = new Demo();
{
if(!(obj instanceof Demo)) //如果不是demo类型
return false;
Demo d = (Demo)obj; //向下转型
return this.num == d.num;
}
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1 = new Demo();
Demo d2 = new Demo();
Demo d2 = d1;
System.out.println(d1.equals(d3));
System.out.println(d1==d2);
System.out.println(d1==d3);
}
}
如果用到了对象中的特有数据 覆写时父类是object类型,要做判断和转换的动作,
09面向对象(Object类-toString())
class ObjectDemo
{
public static void main(String[] args)
{
Demo d1 = new Demo(4);
//一个对象的建立依赖与类文件,进内存时,类文件被封装成对象,类文件里既有构造函数,又有一般方法,还有一个成员变量。要想获取其中一样东西(将其封装成对象,在对象中定义很多功能,这样获取比较方便)。
System.out.println(d1); //输出语句打印对象时,会自动调用对象的toString方法。打印对象的字符串表现形式。
Demo d2 = new Demo(7);
System.out.println(d2.toString());
//Demo d2 = new Demo(5);
//Class c = d1.getClass();
//
// System.out.println(c.getName());
// System.out.println(c.getName()+"@@"+Integer.toHexString(d1.hashCode()));
// System.out.println(d1.toString());
//Person p = new Person();
///System.out.println(d1.equals(p));
}
}
//一个对象有他自己对应的独特的字符串表现形式