如何来改变一个对象的中的既有方法呢?
比如如下代码:
class Dog{
public void bark(){
System.out.println("bark:Wolf-Wolf");
}
public void eat(){
System.out.println("eat:BonesBones");
}
}
public class TestInherit {
public static void main(String[] args) {
Dog dog = new Dog();
dog.bark();
dog.eat();
}
}
我们的目的是将狗叫bark()这个方法改造成另一种实现,这个过程可以有下述的几种方法来实现:
1.继承
Java继承是Java作为面向对象的基础之一,可以用子类方法复写(override)父类方法
class Dog{
public void bark(){
System.out.println("bark:Wolf-Wolf");
}
public void eat(){
System.out.println("eat:BonesBones");
}
}
class InhDog extends Dog{
public void bark() {
System.out.println("bark:WangWangWang");
}
}
public class TestInherit {
public static void main(String[] args) {
Dog dog = new InhDog();
dog.bark();
dog.eat();
}
}
InhDog继承Dog后生成的dog对象拥有Dog的类型却具有InhDog的方法,调用其bark()方法时会调用子类复写的方法,这个过程也是Java多态性的体现。
Dog dog = new InhDog();
这一句执行使,调用InhDog的构造方法,构造的对象在内存中保存的方法和属性都是子类具有的,用Dog父类去接使得这个对象变量的类型是父类Dog类型。
继承修改的方法虽然简单,但是一个已经生成的对象是不能使用继承来进行这个方法修改的,因为对象已经生成,它的方法就是父类的方法,不能把它转成子类并进而使用子类方法的。即如果对象已经生成,那么没办法使用继承的办法来改变想要改变的方法。
2.装饰
interface Animal{
public void bark();
public void eat();
}
class Dog implements Animal{
public void bark(){
System.out.println("bark:Wolf-Wolf");
}
public void eat(){
System.out.println("eat:BonesBones");
}
}
class DecDog implements Animal{
private Animal animal = null;
public DecDog(Animal animal){
this.animal = animal;
}
public void bark() {
System.out.println("bark:WangWangWang");
}
public void eat() {
animal.eat();
}
}
public class DecTest {
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = new DecDog(dog);
animal.eat();
animal.bark();
}
}
装饰的实质是将一个类A封装在另一个类B内部,然后用B类来构造A类,而且A,B都实现同一接口,然后A类控制实现不同的方法,如果要对B类方法进行特殊修饰就重写该方法,如果不需要就直接使用B的方法。
这个办法是可以在对象已生成的情况下改变方法的,但是需要对实现的接口进行重新填补抽象方法,抽象方法很多时增加了代码的冗余。
3.动态代理
interface Animal{
public void bark();
public void eat();
}
class Dog implements Animal{
public void bark(){
System.out.println("bark:Wolf-Wolf");
}
public void eat(){
System.out.println("eat:BonesBones");
}
}
public class ProxyTest {
public static void main(String[] args) {
final Dog dog = new Dog();
Animal animal = (Animal) Proxy.newProxyInstance(Dog.class.getClassLoader(), Dog.class.getInterfaces(), new InvocationHandler()
{
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
if("bark".equals(method.getName())){
System.out.println("bark:WangWangWang");
return null;
}
else{
return method.invoke(dog, args);
}
}
});
animal.bark();
animal.eat();
}
}
动态代理的意思是利用代理类来承接原类中的某些方法,本例中使用 Proxy.newProxyInstance方法来创建一个Dog类的代理类实例,代理中定义的invoke方法在每次调用到代理类生成的对象的方法时都会回去访问该函数,比如利用创建出的animal对象的方法bark()时就会去访问InvocationHandler()中的invoke方法,并执行invoke方法。在本例中,虽然和装饰办法一样都采用了Animal类型的animal对象,但是不需要复写其他的抽象方法,只需要把需要复写的方法单独写出即可,其他方法只需要用原来的方法就好。可以看出,在创建好对象后,这个办法是最省力的。