您的位置:首页 > 其它

面向对象之多态

2016-02-21 16:20 295 查看
多态:可以理解为事物存在的多种体现形态。

例如:人:男人,女人;

动物:猫,狗

猫 x = new 猫();

动物 x = new 猫();

从以下几个方面介绍多态:

多态的体现——父类的引用指向了自己的子类对象。父类的引用也可以接收自己的子类对象

多态的前提——必须是类与类之间有关系,要么继承,要么实现。通常还有一个前提:存在覆盖

多态的好处——多态的出现大大的提高了程序的扩展性

多态的弊端——提高了扩展性,但是只能使用父类的引用访问父类中的成员,不能预先使用子类,因为那时子类还没存在

多态的应用

多态的出现在代码中的特点(多态使用的注意事项)

以动物:猫,狗,猪为例说之

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 PolDemo {

public static void main(String[] args) {
//        Cat c = new Cat();
//        c.eat();
//
//        Dog d = new Dog();
//        d.eat();
//        Cat c = new Cat();
//        function(c);
//
//        function(new Dog());
//
//        function(new Pig());

//        Animal c = new Cat();
//        c.eat();

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(Animal a) { //Animal a = new Cat();
a.eat();
//        a.catchMouse();
/*if(a instanceof Animal) {
System.out.println("hello");
} else*/ if(a instanceof Cat) {
Cat c = (Cat)a;
c.catchMouse();
} else if(a instanceof Dog) {
Dog d = (Dog)a;
d.KanJia();
}

}
/*
public static void function(Cat c) { //Cat c = new Cat();
c.eat();
}

public static void function(Dog d) {
d.eat();
}

public static void function(Pig p) {
p.eat();
}
*/
}


以下例说明多态的应用:

基础班学生:学习,睡觉

高级班学生:学习,睡觉

可以将这两类事物进行抽取。

代码如下:

abstract class Student {
public abstract void study();
public void sleep() {
System.out.println("躺着睡");
}
}
//工具类
class DoStudent {
public void doSomething(Student s) {
s.study();
s.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");
}
}

public class DuoTaiDemo {

public static void main(String[] args) {
DoStudent ds = new DoStudent();
ds.doSomething(new BaseStudent());
ds.doSomething(new AdvStudent());
//        BaseStudent bs = new BaseStudent();
//        bs.study();
//        bs.sleep();
//        AdvStudent as = new AdvStudent();
//        as.study();
//        as.sleep();
}

}


以下例说明多态的出现在代码中的特点(多态使用的注意事项)

在多态中成员函数(非静态)的特点:

在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败。

在运行时期:参阅对象所属的类中是否有调用的方法。

简单总结就是:

成员函数(非静态)在多态调用时,编译看左边,运行看右边。

在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属的类)

在多态中,静态成员函数的特点:无论编译和运行,都参考左边。

示例代码如下:

class Fu {

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 {

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");
}

}
public class DuoTaiDemo1 {

public static void main(String[] args) {
/*
* 在多态中,成员变量的特点:无论编译和运行,都参考左边(引用型变量所属 的类)
*/
//        Fu f = new Zi();
//        System.out.println(f.num);
//
//        Zi z = new Zi();
//        System.out.println(z.num);

/*
* 在多态中,静态成员函数的特点:无论编译和运行,都参考左边。
*/
Fu f = new Zi();
f.method4();
Zi z = new Zi();
z.method4();

/*
* 在多态中成员函数(非静态)的 特点:在编译时期:参阅引用型变量所属的类中是否有调用的方法,如果有,编译通过,如果没有编译失败
*                在运行时期:参阅对象所属的类中是否有调用的方法
* 简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。
*/
//        Fu f = new Zi();
//        f.method1();
//        f.method2();
//        f.method3();

}
}


多态的应用:

1、电脑运行示例,电脑运行基于主板

代码示例如下:

//接口定义规则
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 DuoTaiDemo2 {

public static void main(String[] args) {
MainBoard mb = new MainBoard();
mb.run();
mb.usePCI(null);
mb.usePCI(new NetCard());
mb.usePCI(new SoundCard());
}

}


2、数据库的操作。数据是:用户信息。

连接数据库(JDBC Hibernate)

操作数据库(CRUD)——C creat R read U update D delete

关闭数据库连接

代码示例如下:

interface UserInfoDao { //dao: d(data) a(access) o(object)——数据访问对象
public void add(User user);
public void delete(User user);
}
class UserInfoByJDBC implements UserInfoDao {
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、关闭连接
}
}
public class DBOperate {

public static void main(String[] args) {
//        UserInfoByJDBC ui = new UserInfoByJDBC();
//        UserInfoByHibernate ui = new UserInfoByHibernate();
UserInfoDao ui = new UserInfoByJDBC(); //多态
ui.add(user);
ui.delete(user);
}

}


Object类

Object:是所有对象的直接或者间接父类,传说中的上帝。该类中定义的肯定是所有对象都具备的功能。

Object类中已经提供了对对象是否相同的比较方法,如果自定义类中也有比较相同的功能,没有必要重新定义。只要沿袭父类中的功能,建立自己特有比较内容即可,这就是覆盖。

内部类

内部类的访问规则:

内部类可以直接访问外部类中的成员,包括私有。之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类中的引用,格式--外部类名.this

外部类要访问内部类,必须建立内部类对象

访问格式:

1、当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中,可以直接建立内部类对象。

格式:外部类名.内部类名 变量名 = 外部类对象.内部类对象

Outer.Inner in = new Outer().new Inner();

2、当内部类在成员位置上,就可以被成员修饰符修饰,比如,private将内部类在外部类中进行封装,static内部类就具备static的特性。当内部类被static修饰后,只能直接访问外部类中的static成员,出现了访问局限。

在外部其他类中,如何直接访问静态内部类非静态成员呢?

new Outer.Inner().function();

在外部其他类中,如何直接访问静态内部类静态成员呢?

Outer.Inner.function();

注意:当内部类中定义了静态成员,该内部类必须是static的。当外部类中的静态方法访问内部类时,内部类也必须是static的。

示例代码如下:

class Outer {
private static int x = 3;

static class Inner {//内部类可以被私有修饰(静态内部类)
//        int x = 4;
static void function() {
//            int x = 6;
System.out.println("inner:"+x);
}
}

static class Inner2 {
void show() {
System.out.println("inner2 show");
}
}

public static void method() {
//        Inner in = new Inner();
//        in.function();

//        Inner.function();
new Inner2().show();
}
}

public class InnerClassDemo {

public static void main(String[] args) {

Outer.method();
//        Outer.Inner.function();
//        Outer out = new Outer();
//        out.method();

//直接访问内部类中的成员
//        Outer.Inner in = new Outer().new Inner();
//        in.function();
}

}


内部类什么时候使用呢?

当描述事物时,事物的内部还有事物,该事物用内部类来描述,因为内部事物在使用外部事物的内容。以人体和心脏为例进行说明之(示例代码如下)

//人体(外部类)
class Body {
//心脏(内部类)
private class XinZang { //心脏得封装起来

}
public void show() {
new XinZang().tiaoDong();
}
}


内部类定义在局部时

不可以被成员修饰符修饰,因为private、static不能修饰局部成员

可以直接访问外部类中的成员,因为还持有外部类中的引用。但是不可以访问它所在的局部中的变量,只能访问被final修饰的局部变量,java8好像没这个区别了

示例代码如下:

class Outer_P {

int x = 3;

void method(final int a) {
final int y = 4;
class Inner { //private、static不能修饰局部成员
void function() {
//                System.out.println(Outer_P.this.x);
//                System.out.println(y);
System.out.println(a);
}
}
new Inner().function();
}
}
public class InnerClassDemo1 {

public static void main(String[] args) {
Outer_P out = new Outer_P();
out.method(7);
out.method(8);
}

}


匿名内部类

匿名内部类其实就是内部类的简写格式

定义匿名内部类的前提:内部类必须是继承一个类或者实现接口

匿名内部类的格式:new 父类或者接口() {定义子类的内容}

匿名内部类其实就是一个匿名子类对象,而且这个对象有点胖。可以理解为带内容的对象

匿名内部类中定义的方法最后不要超过3个。

示例代码如下:

abstract class AbsDemo {
abstract void show();
}
class Outer_I {
int x  =3;
/*
class Inner extends AbsDemo {
int num = 90;
void show() {
System.out.println("show:"+num);
}
void abc() {
System.out.println("haha");
}
}
*/

public void function() {
//        new Inner().show();

//        Inner in = new Inner();
//        in.show();
//        in.abc();

//AbsDemo a = new Inner();
//new AbsDemo(){}是一个AbsDemo的匿名子类对象
AbsDemo d = new AbsDemo() {
int num = 9;
void show() {
System.out.println("num==="+num);
}
//子类特有方法
void abc() {
System.out.println("haha");
}
};
d.show();
//        d.abc();//编译失败
new AbsDemo() {
void show() {
System.out.println("x="+x);
}
//子类特有方法
void abc() {
System.out.println("haha");
}
}.abc();

}
}
public class InnerClassDemo2 {

public static void main(String[] args) {
new Outer_I().function();
}

}


练习:补全代码。通过匿名内部类

示例代码:

interface Inter {
void method();
}
class Test {
/*
static class Inner implements Inter {
public void method() {
System.out.println("method run");
}
}
static Inter function() {
return new Inner();
}
*/
//补足代码。通过匿名内部类
static Inter function() {
return new Inter() {
public void method() {
System.out.println("haha");
}
};
}
}

public class InnerClassTest {

public static void main(String[] args) {
//Test.function():Test类中有一个静态的方法function
//.method():function这个方法运算后的结果是一个对象,而且是一个Inter类型的对象,因为只有是Inter类型的对象,才可以调用method().
Test.function().method();

//        Inter in = Test.function();
//        in.method();
show(new Inter() {
public void method() {
System.out.println("main run");
}
});
}

public static void show(Inter in) {
in.method();
}

}


面试时可能遇到的一个小问题(有关匿名内部类),如果没有一个类继承或一个抽象类实现,还能使用匿名内部类吗?答案是可以的。示例代码如下:

class InnerTest {

public static void main(String[] args) {
new Object() {// new Object() {}是Object类的子类对象
public void function() {
System.out.println("hello");
}
}.function();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: