0%

翻译自:http://developer.android.com/training/articles/perf-tips.html 一、避免创建不必要的对象 1、如果一个方法返回String,而这个返回值要附加到StringBuffer,那么,应该直接append(方法),不要再有中间临时变量。 2、当从一组输入数据中提取字符串时,尝试使用子串,不要创建一个拷贝。你会创建一个新的String,但是会与原数据共享char[]。需要权衡的是,所有原始输入数据都在在内存中,如果你只使用原数据的一小部分,会浪费一些内存。 更激进彻底的方法是,把多维数组转成多个一维数组。 1、int数组比Integer数组更好,两个平行数组int[]比一个二维数组int[][]更有效,其他基本类型也一样 2、如果要实现一个容器类来保存Foo、Bar,记住:两个一维数组Foo[]和Bar[]比容器数组更高效。(如果是开发提供给别人使用的API,还是使用类封装一下比较好,更容易理解。但自己用的话,你应该尝试更高效的写法) 一般而言,尽可能避免创建短期临时变量。越少的对象创建,意味着GC的频率越低,对提升用户体验有直接效果。 二、使用static 如果不需要访问实例变量,应该把方法声明成static,调用速度会提高15%-20%。这也是一个很好的实践,因为你可以从方法声明辨认出该方法不能改变对象状态。 三、常量使用static final 看下面的声明:

static int intVal = 42;
static String strVal = "Hello, world!";

编译器生成一个叫的类初始化方法,当类第一次加载时执行。该方法保存42到intVal,并且从class文件的string常量表提取一个引用给strVal。当这些值被引用的时候,通过字段查找来找到这些变量。 可以通过加入final来改善:

static final int intVal = 42;
static final String strVal = "Hello, world!";

该类不再需要方法,因为常量进入dex文件的静态字段初始化器中,引用intVal的代码将会直接使用42,而访问strVal会使用相对高效的”string constant” 指令替代字段查找。这条优化建议只适用于原始数据类型和String,非所有引用类型。但尽可能地用static final声明常量是一条很好的实践。 尼玛,上面是直接翻的,自己感觉都看不懂,我的理解是,编译生成的class文件,所有引用intVal的地方直接换成了42,而字符串,会有一个常量池,不知道对不对。 四、避免内部调用Getter/Setter 在像C++这样的Native(相对Java的虚拟机)语言中,通常做法是使用Getter(i = getCount())代替直接访问字段(i = mCount),这是一个极好的习惯,并且在其他面向对象语言中像C#,Java也经常这么用,因为编译器通常可以内联访问,并且如果你需要限制访问或Debug字段访问,可以随时在setter/getter中添加代码。 然而,在Android这样做不是个主意。Virtual method调用是非常昂贵的,远超字段查找。跟随通用的面对对象编程实践,使用Getter/Setter是合理的,但在一个类中,你应该直接访问字段。(根据wikipedia,Virtual method指的是可以被子类覆盖的方法,http://en.wikipedia.org/wiki/Virtual_function) 没有JIT,直接访问字段比调用Getter快3倍,有JIT(字段访问与局部变量访问开销一样),直接访问字段比调用Getter快7倍。 如果你用ProGuard,你可以鱼与熊掌兼得,因为ProGuard会内联存取器(setter/getter). 五、使用增强的for循环语法。 增强的for循环(for-each)可以用于实现Iterable接口的集合和数组。在集合中,迭代器分配给接口调用hasNext() 和next()方法。使用ArrayList,hand-written counted loop大概要快3倍(不管有没有JIT),但是其他集合类使用for-each循环和显示使用迭代器相当。 注:hand-written counted loop,我也不知道是啥,我猜应该是for(int i=0;i static class Foo { int mSplat; } Foo[] mArray = ... public void zero() { int sum = 0; for (int i = 0; i < mArray.length; ++i) { sum += mArray[i].mSplat; } } public void one() { int sum = 0; Foo[] localArray = mArray; int len = localArray.length; for (int i = 0; i < len; ++i) { sum += localArray[i].mSplat; } } public void two() { int sum = 0; for (Foo a : mArray) { sum += a.mSplat; } } zero()最慢,因为JIT还不能优化在循环中每次迭代获取数组长度的开销。 one()较快,它把所有变量放到了局部变量中,避免了查找,数组长度只需要读一次。 two()在没有JIT的设备中最快。在有JIT的设备中,与one()相同。它使用了在Java 1.5(5.0)中介绍的增强的for循环。 所以,除了ArrayList外,能用for each的都用for each. 六、使用package代替内部private类访问内部private字段方法。 水平有限,这段不翻了,从举的例子来看大部分人也不会这么用,最终原因参考以上第四条,因为内部私有类访问内部私有字段方法会转换成访问Setter/Getter,建议把private换成package(默认) 七、避免使用Float 一般来说,在Android设备上,浮点数要比整数慢2倍。 在速度上,float和double在现代的设备上没有什么区别,在空间上,double是float的两倍。在电脑上,假设空间不是问题,你应该使用double而不是float. 同样,即使是整数,一些处理器有硬件乘法而没有硬件除法。In such cases, integer division and modulus operations are performed in software—something to think about if you’re designing a hash table or doing lots of math.好吧,这句不会翻。 八、了解并使用库 这条偷懒。Google写的代码通常比你自己写的性能好,有现成的库就用现成的。System.arraycopy()在Nexus one上比手写循环快9倍。 九、小心使用Native方法 使用NDK写Native代码不一定比用Java写更高效。首先,JNI转换有消耗,并且JIT不能优化。如果你分配了Native资源(堆内存,文件或其他),回收资源更麻烦。你还需要为每个需要支持的构架编译so文件(而不是依靠JIT),你甚至不得不为相同的构架编译多个不同的版本,为G1 ARM处理器编译的Native代码,在Nexus one的Arm处理器上不能充分利用.为Nexus one的ARM处理器编译的native代码不能在G1上工作。当你想把现有的Native代码库移植到Android上是,Native代码是很有用的,但不能为了加速你的应用而把Java换成Native. 十、性能误区 在没有JIT的设备上,调用一个准确类型变量的方法比调用该类型实现接口的方法稍微高效一些(向上转型要低效一些).举例来说,声明HashMap map比声明Map map更高效,即使两个都是HashMap.大概有6%的性能损失,用了JIT,基本没区别。 在没有JIT的设备中,缓存字段访问比重复访问字段要快20%,有JIT,字段访问与局部变量访问开销一样,所以这不值得你去优化,除非你觉得这使代码可读性更高。(这条对static,final,static final同样适用) 十一、测量 在你开始优化之前,确保你有问题需要解决(没问题优化个毛)。确保你能精确的测量你已存在的性能,否则你不能衡量修改后的好处。

listview有个setSelection方法,在SingleChoiceMode下,经实验无效,获取选中项是用getCheckedItemPosition(),不是getSelectedItemId()。如果要给用户默认选中一项呢?可以调用performItemClick方法,顾名思义,该方法就是触发Item点击事件,也就实现了选中指定项的功能。 选中第0项:

boolean b=listview_selection.performItemClick(listview_selection.getAdapter().getView(0, null, null), 0, 0);

命令模式由三部分组成: Receiver:命令接收者,最终执行命令的角色 Command:待执行的命令 Invoker:调用者,接收到Command后让Receiver执行 代码来自《您的设计模式》. Receiver:

package com.pocketdigi.patterns.command;
/**
 * Receiver,命令执行者
 */
public abstract class Group {
    public abstract void find();
    public abstract void add();
    public abstract void delete();
    public abstract void change();
    public abstract void plan();
}




package com.pocketdigi.patterns.command;
/**
 * 代码组
 */
public class CodeGroup extends Group {

    @Override
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("找到代码组");
    }

    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("客户要求增加一项功能");

    }

    @Override
    public void delete() {
        // TODO Auto-generated method stub
        System.out.println("客户要求删除一项功能");
    }

    @Override
    public void change() {
        // TODO Auto-generated method stub
        System.out.println("客户要求修改一项功能");
    }

    @Override
    public void plan() {
        // TODO Auto-generated method stub
        System.out.println("客户要求代码变更计划");
    }

}




package com.pocketdigi.patterns.command;
/**
 * 美工组
 */
public class PageGroup extends Group {

    @Override
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("找到美工组");
    }

    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("客户要求增加一个页面 ");

    }

    @Override
    public void delete() {
        // TODO Auto-generated method stub
        System.out.println("客户要求删除一个页面");
    }

    @Override
    public void change() {
        // TODO Auto-generated method stub
        System.out.println("客户要求修改一个页面");
    }

    @Override
    public void plan() {
        // TODO Auto-generated method stub
        System.out.println("客户要求页面变更计划");
    }

}



package com.pocketdigi.patterns.command;

/**
 * 需求组
 */
public class RequirementGroup extends Group {

    @Override
    public void find() {
        // TODO Auto-generated method stub
        System.out.println("找到需求组");
    }

    @Override
    public void add() {
        // TODO Auto-generated method stub
        System.out.println("客户要求增加一项需求 ");

    }

    @Override
    public void delete() {
        // TODO Auto-generated method stub
        System.out.println("客户要求删除一项需求");
    }

    @Override
    public void change() {
        // TODO Auto-generated method stub
        System.out.println("客户要求修改一项需求");
    }

    @Override
    public void plan() {
        // TODO Auto-generated method stub
        System.out.println("客户要求需求变更计划");
    }

}

Command:

package com.pocketdigi.patterns.command;

public abstract class Command {
    protected RequirementGroup rg=new RequirementGroup();
    protected PageGroup pg=new PageGroup();
    protected CodeGroup cg=new CodeGroup();
    
    public abstract void execute();
}



package com.pocketdigi.patterns.command;
/**
 * 添加需求Command
 */
public class AddRequirementCommand extends Command {

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        super.rg.find();
        super.rg.add();
        super.rg.plan();
    }

}




package com.pocketdigi.patterns.command;
/**
 * 添加需求Command
 */
public class DeletePageCommand extends Command {

    @Override
    public void execute() {
        // TODO Auto-generated method stub
        super.pg.find();
        super.pg.delete();
        super.pg.plan();
    }

}

Invoker:

package com.pocketdigi.patterns.command;

/**
 * 命令接收,执行
 */
public class Invoker {
    private Command command;
    public void setCommand(Command command)
    {
        this.command=command;
    }
    public void action()
    {
        command.execute();
    }
}

使用:

        //命令模式
        Invoker invoker=new Invoker();
        invoker.setCommand(new DeletePageCommand());
        invoker.action();

桥梁模式特点在于,多个维度都可自由扩展,而继承只能向一个维度扩展。 代码来自《您的设计模式》

package com.pocketdigi.patterns.bridge;

public abstract class Product {
    public abstract void beProducted();
    public abstract void beSelled();
}



package com.pocketdigi.patterns.bridge;
/**
 * 可根据需求扩展crop类
 */
public class HouseCrop extends Crop {
    /**
     * 只能生产House,所以参数为House,不是Product
     * @param product
     */
    public HouseCrop(House product) {
        super(product);
        // TODO Auto-generated constructor stub
    }
    @Override
    public void makeMoney() {
        // TODO Auto-generated method stub
        super.makeMoney();
        System.out.println("房地产公司赚大钱了...");
    }

}



package com.pocketdigi.patterns.bridge;
/**
 * 扩展Crop
 */
public class ShanZhaiCrop extends Crop {

    /**
     * 根据传入的Product不同,生产出不同的产品
     * @param product
     */
    public ShanZhaiCrop(Product product) {
        super(product);
        // TODO Auto-generated constructor stub
    }
    @Override
    public void makeMoney() {
        // TODO Auto-generated method stub
        super.makeMoney();
        System.out.println("我赚钱啦...");
    }

}



package com.pocketdigi.patterns.bridge;
/**
 * 产品,也可以根据需求自由扩展
 */
public abstract class Product {
    public abstract void beProducted();
    public abstract void beSelled();
}



package com.pocketdigi.patterns.bridge;

public class House extends Product {

    @Override
    public void beProducted() {
        // TODO Auto-generated method stub
        System.out.println("生产出的房子是这样的...");
    }

    @Override
    public void beSelled() {
        // TODO Auto-generated method stub
        System.out.println("生产出的房子卖出去了...");
    }

}



package com.pocketdigi.patterns.bridge;

public class Clothes extends Product {

    @Override
    public void beProducted() {
        // TODO Auto-generated method stub
        System.out.println("生产出的衣服是这样的...");
    }

    @Override
    public void beSelled() {
        // TODO Auto-generated method stub
        System.out.println("生产出的衣服卖出去了...");
    }

}




package com.pocketdigi.patterns.bridge;

public class IPod extends Product{

    @Override
    public void beProducted() {
        // TODO Auto-generated method stub
        System.out.println("生产出的IPod是这样的...");
    }

    @Override
    public void beSelled() {
        // TODO Auto-generated method stub
        System.out.println("生产出的IPod卖出去了...");
    }

}

使用:

        //桥梁模式
        Crop crop1=new HouseCrop(new House());
        crop1.makeMoney();
        
        Crop crop2=new ShanZhaiCrop(new Clothes());
        crop2.makeMoney();
        
        Crop crop3=new ShanZhaiCrop(new IPod());
        crop3.makeMoney();

代码转自:http://www.importnew.com/6841.html 建造者模式,使用不同的Builder,构建出形态不同的产品。与工厂模式最大区别在于,建造者模式最主要的功能是基本方法调用顺序的安排,而工厂方法重点在创建对象,不关心基本方法调用顺序

package com.pocketdigi.patterns.builder;

/**
 * 最终构建出的产品
 */
public class Starbucks {
    private String size;
    private String drink;
    public void setSize(String size) {
        this.size = size;
    }
    public void setDrink(String drink) {
        this.drink = drink;
    }
    
}



package com.pocketdigi.patterns.builder;
/**
 * 抽象建造者
 */
public abstract class StarbucksBuilder {
    protected Starbucks starbucks;

    public Starbucks getStarbucks() {
        return starbucks;
    }
    public void createStarbucks()
    {
        starbucks=new Starbucks();
        System.out.println("a drink is created");
    }
    
    public abstract void buildSize();
    public abstract void buildDrink();
}



package com.pocketdigi.patterns.builder;
/**
 * Tea建造者
 */
public class TeaBuilder extends StarbucksBuilder {

    @Override
    public void buildSize() {
        // TODO Auto-generated method stub
        starbucks.setSize("large");
        System.out.println("build large size");
    }

    @Override
    public void buildDrink() {
        // TODO Auto-generated method stub
        starbucks.setDrink("tea");
        System.out.println("build tea");
    }

}



package com.pocketdigi.patterns.builder;
/**
 * Tea建造者
 */
public class CoffeeBuilder extends StarbucksBuilder {

    @Override
    public void buildSize() {
        // TODO Auto-generated method stub
        starbucks.setSize("medium");
        System.out.println("build medium size");
    }

    @Override
    public void buildDrink() {
        // TODO Auto-generated method stub
        starbucks.setDrink("Coffee");
        System.out.println("build Coffee");
    }

}



package com.pocketdigi.patterns.builder;
/**
 * Builder封装
 */
public class Waiter {
    private StarbucksBuilder starbucksBuilder;

    public Starbucks getStarbucksDrink() {
        return starbucksBuilder.getStarbucks();
    }

    public void setStarbucksBuilder(StarbucksBuilder starbucksBuilder) {
        this.starbucksBuilder = starbucksBuilder;
    }
    
    public void build()
    {
        starbucksBuilder.createStarbucks();
        starbucksBuilder.buildDrink();
        starbucksBuilder.buildSize();
    }
}

调用:

        //建造者模式
        Waiter waiter=new Waiter();
        StarbucksBuilder starbuksBuilder=new TeaBuilder();
        waiter.setStarbucksBuilder(starbuksBuilder);
        waiter.build();
        Starbucks starBucks=waiter.getStarbucksDrink();

原先老版本的系统,只需要在AndroidManifest.xml中声明Activity时加上android:configChanges=”orientation|keyboardHidden”,切换屏幕方法时就不会重建Activity,不会再执行onCreate方法,但新版的Android(Api 13以后),在屏幕切换时screen size也会改变,导致上面的方法无效,所以还要加上screenSize,改成 android:configChanges=”orientation|keyboardHidden|screenSize” 即可,会调用Activity中的onConfigurationChanged方法.

模板方法模式是由模板(抽象类)定义子方法执行顺序,子类实现子方法,其实很简单,我们平时很常用,只是不知道这个叫模板方法模式罢了。 定义模板(父类):

package com.pocketdigi.patterns.templatemethod;

public abstract class HummerModel {
    /**
     * 这个叫基本方法,子类可以覆盖
     * 基本方法分三类,在抽象类中实现了的基本方法叫做具体方法;
     * 在抽象类中没有实现,在子类中实现了叫做抽象方法
     * 可以改变模板方法行为的叫钩子方法
     * 不允许外部直接调用这些方法,所以用protected
     */
    protected abstract void start();
    protected abstract void stop();
    protected abstract void alarm();
    protected abstract void engineBoom();
    /**
     * 这个叫钩子方法
     * @return
     */
    protected boolean isAlarm()
    {
        return true;
    }
    /**
     * 定义了其他方法的执行顺序,并且子类不能修改,叫模板方法
     */
    public final void run(){
        start();
        engineBoom();
        //钩子方法改变行为
        if(isAlarm())
        {
            alarm();
        }
        stop();
        
    }
}

不同的子类实现:

package com.pocketdigi.patterns.templatemethod;

public class HummerH1 extends HummerModel {

    @Override
    protected void start() {
        // TODO Auto-generated method stub
        System.out.println("悍马H1启动");
    }

    @Override
    protected void stop() {
        // TODO Auto-generated method stub
        System.out.println("悍马H1停止");
    }

    @Override
    protected void alarm() {
        // TODO Auto-generated method stub
        System.out.println("悍马H1鸣笛");
    }

    @Override
    protected void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("悍马H1引擎轰鸣");
    }

}



package com.pocketdigi.patterns.templatemethod;

public class HummerH2 extends HummerModel {
    boolean isAlarm;
    @Override
    protected void start() {
        // TODO Auto-generated method stub
        System.out.println("悍马H2启动");
    }

    @Override
    protected void stop() {
        // TODO Auto-generated method stub
        System.out.println("悍马H2停止");
    }

    @Override
    protected void alarm() {
        // TODO Auto-generated method stub
        System.out.println("悍马H2鸣笛");
    }

    @Override
    protected void engineBoom() {
        // TODO Auto-generated method stub
        System.out.println("悍马H2引擎轰鸣");
    }
    /**
     * 覆盖钩子方法
     */
    @Override
    protected boolean isAlarm() {
        // TODO Auto-generated method stub
        return isAlarm;
    }

    public void setAlarm(boolean isAlarm) {
        this.isAlarm = isAlarm;
    }
    
}

当自身系统接入第三方系统(调用第三方接口)时,Model一般都是不一样的,解决方法一般有两种,一是单独为每个第三方接口开发相应的功能,二是使用适配器模式,把第三方返回的对象转换成我们系统定义的对象。使用适配器模式,是现有系统修改最小的方案。 下面的例子假设两个系统的User类定义不同,需要交互。 本地IUser接口:

package com.pocketdigi.patterns.adapter;

public interface IUser {
    public String getUserName();
    public String getUserId();
    public String getPassword();
}

实现类:

package com.pocketdigi.patterns.adapter;

public class UserImp implements IUser {
    String userName;
    String userId;
    String password;
    @Override
    public String getUserName() {
        // TODO Auto-generated method stub
        return userName;
    }

    @Override
    public String getUserId() {
        // TODO Auto-generated method stub
        return userId;
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return password;
    }

}

另一个系统的User:

package com.pocketdigi.patterns.adapter;

/**
 * 假设这是另一个系统中的User对象
 * 
 */
public class UserInfo {
    String user;
    String id;
    String pwd;
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    
}

适配器模式又分对象适配器模式和类适配器模式 下面是类适配模式:

package com.pocketdigi.patterns.adapter;
/**
 * 类适配器模式
 */
public class UserAdapter1 extends UserInfo implements IUser {

    @Override
    public String getUserName() {
        // TODO Auto-generated method stub
        return this.getUser();
    }

    @Override
    public String getUserId() {
        // TODO Auto-generated method stub
        return this.getId();
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return this.getPwd();
    }

}

对象适配模式:

package com.pocketdigi.patterns.adapter;
/**
 * 对象适配器模式
 */
public class UserAdapter2 implements IUser {
    UserInfo info;
    public UserInfo getInfo() {
        return info;
    }

    public void setInfo(UserInfo info) {
        this.info = info;
    }

    @Override
    public String getUserName() {
        // TODO Auto-generated method stub
        return info.getUser();
    }

    @Override
    public String getUserId() {
        // TODO Auto-generated method stub
        return info.getId();
    }

    @Override
    public String getPassword() {
        // TODO Auto-generated method stub
        return info.getPwd();
    }

}

外观模式(Facade Pattern),将一个操作要完成的子步骤整合到一个方法里,调用者无需担心调用顺序,以及具体的子步骤。

package com.pocketdigi.patterns.facade;
/**
 * 信件处理接口
 */
public interface LetterProcess {
    public void writeContext(String context);
    public void fillEnvelope(String address);
    public void letterIntoEnvelope();
    public void sendLetter();
}

实现

package com.pocketdigi.patterns.facade;

public class LetterProcessImp implements LetterProcess {

    @Override
    public void writeContext(String context) {
        // TODO Auto-generated method stub
        System.out.println("写内容"+context);
    }

    @Override
    public void fillEnvelope(String address) {
        // TODO Auto-generated method stub
        System.out.println("写信封"+address);
    }

    @Override
    public void letterIntoEnvelope() {
        // TODO Auto-generated method stub
        System.out.println("装信封");
    }

    @Override
    public void sendLetter() {
        // TODO Auto-generated method stub
        System.out.println("送信");

    }

}



package com.pocketdigi.patterns.facade;

public class PostOffice {
    LetterProcess letterProcess=new LetterProcessImp();
    /**
     * 将几个步骤并在一起,调用者不需要具体的实现过程
     * @param context
     * @param address
     */
    public void sendLetter(String context,String address)
    {
        letterProcess.writeContext(context);
        letterProcess.fillEnvelope(address);
        letterProcess.letterIntoEnvelope();
        letterProcess.sendLetter();
    }
}

调用

        PostOffice po=new PostOffice();
        po.sendLetter("内容", "地址");

其实工厂模式跟策略模式有点相似,只不过,策略模式是通过中Contex调用具体实现类的相应方法,而工厂模式是生成实现类的实例。

package com.pocketdigi.patterns.factory;

public interface Human {
    public void laugh();
    public void cry();
}



package com.pocketdigi.patterns.factory;

public class YellowHuman implements Human {
    /**
     * 不加public 使得在外包无法new
     */
    YellowHuman()
    {
        
    }
    @Override
    public void laugh() {
        // TODO Auto-generated method stub
        System.out.println("黄色人种笑");
    }

    @Override
    public void cry() {
        // TODO Auto-generated method stub
        System.out.println("黄色人种哭");
    }
}



package com.pocketdigi.patterns.factory;

public class BlackHuman implements Human {
    /**
     * 不加public 使得在外包无法new
     */
    BlackHuman()
    {
        
    }
    @Override
    public void laugh() {
        // TODO Auto-generated method stub
        System.out.println("黑色人种笑");
    }

    @Override
    public void cry() {
        // TODO Auto-generated method stub
        System.out.println("黑色人种哭");
    }
}

工厂:

package com.pocketdigi.patterns.factory;


public class HumanFactory {
    public static Human createHuman(Class c)
    {
        try {
            Object obj=c.newInstance();
            return (Human)obj;
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return null;
    }

    public static BlackHuman createBlackHuman()
    {
        return (BlackHuman)createHuman(BlackHuman.class);
    }
    
    public static YellowHuman createYellowHuman()
    {
        return (YellowHuman)createHuman(YellowHuman.class);
    }
}

调用:

        Human human=HumanFactory.createHuman(YellowHuman.class);
        human.laugh();
        HumanFactory.createBlackHuman().laugh();