首页 > 学院 > 开发设计 > 正文

java基础提高篇——对象的创建

2019-11-15 00:15:34
字体:
来源:转载
供稿:网友
java基础提高篇——对象的创建

我一直使用构造器的方式生成或者初始化对象。最近发现一些对象在项目中并没有实际作用,有时我只是需要它的一些功能,为此新建一个对象是不是比较消耗资源,影响程序的性能呢。今天看到一些资料,对这个问题作出了一个回答。

说明:

首先肯定的是,我们有时候并不需要一个类的全部功能,或许我们需要的只是其中的一两个方法,没必要为此新建一个类。静态方法解决了这个问题。静态方法应该成为每个面向对象设计程序者必修课程。首先我们学习静态方法创建对象。

使用静态工厂的方式产生对象的好处有这样几个好处:“一:静态方法都有名字,使得你更明白自己在干什么”;“二:使用静态方法不必在每次创建对象,节省了内存”;“三:更灵活,可以返回原返回类型的任何子类型的对象”“四:代码看起来更简洁”;当然它也有缺点的,其中一个主要的缺点是,如果使用静态方法产生对象,那么似乎就可以不包含公有或者受保护的构造器,这样的话子类想继承的话就是不可能的事了。这个可以通过复合避开继承来解决这个问题。

下面将介绍几个比较著名的静态构造器的例子。

第一个例子:多参数类

考虑这个一个需求,我需要建一个类。这个类是用来描述商品的产品说明的,那么这个类就会有很多的参数,并且在每个对象对这个类中的参数需求都是不同的。如果使用重叠构造器,你需要写很多的构造器,最多需要2的n次方个构造器。当然我不会这样写,我会使用javaBeans模式生成get、set方式。这种方式有缺点,老实说以我现在还看不到这样写的危害,似乎是在多线程中是不安全的。这里还是推荐给大家一个更安全更完善的构造方法:

使用builder模式来生成对象。大概的想法是这样的:在这种多参数类的内部构建一个builder的内部类,使用内部类接收传参,最后才是更新外部类的参数。这样做的好处可以是事前检测数据的合法性,对于不合法的数据可以事先处理掉,保证了数据的安全性。这里给出一个例子(要编写以及使用这样的类,你需要知道内部类的语法),

public class BuiltTest {    PRivate String name1, name2, name3, name4, name5, name6, name7;        /*     * 内部类builder     */    public static class Built {        private String name1, name2, name3, name4, name5, name6, name7;        public Built setname1(String name1) {            this.name1 = name1;            return this;        }        public Built setname2(String name2) {            this.name2 = name2;            return this;        }        public Built setname3(String name3) {            this.name3 = name3;            return this;        }        public Built setname4(String name4) {            this.name4 = name4;            return this;        }        public Built setname5(String name5) {            this.name5 = name5;            return this;        }        public Built setname6(String name6) {            this.name6 = name6;            return this;        }        public Built setname7(String name7) {            this.name7 = name7;            return this;        }        public BuiltTest built() {            return new BuiltTest(this);        }    }        //构造方法    private BuiltTest(Built built) {        this.name1 = built.name1;        this.name2 = built.name2;        this.name3 = built.name3;        this.name4 = built.name4;        this.name5 = built.name5;        this.name6 = built.name6;        this.name7 = built.name7;    }        //重写toSting方法    @Override    public String toString() {        String str="My name is "+name1+","+name2+","+name3+","+name4+","+name5+","+name6+","+name7;        return str;    }}

调用的代码:

//创建一个BuiltTest对象BuiltTest a=new BuiltTest.Built().setname1("xiaohua").setname2("小小").setname3("安徽").built();

这种builder方法建立起来的对象,经过测试在参数大于等于4时,性能是更优的。考虑到程序的扩展性,最好一开始就使用builder的构造器。

第二个例子:强化Singleton属性

在一些程序中,为了数据安全,我们仅需要一个对象,这时我们需要Singleton模式。Singleton有三种写法,第一种定义一个Singleton的常量,第二种方法使用工厂的方式返回一个Singleton的对象,第三种方式是返回一个枚举类型的对象。

//第一种方式,产生一个final的对象,私有化构造方法public class Elvis {    public static final Elvis INSTANC_ELVIS = new Elvis();    private Elvis() {    }}
//第二章方法,又构造器产生一个Singleton的对象public class Elvis {    private  static final Elvis INSTANC_ELVIS = new Elvis();    private Elvis() {    }        public Elvis getElvis(){        return INSTANC_ELVIS;    }}
//第三种方法,编写一个enum 类public enum Elvis {    INSTANC_ELVIS;    }

这里简单介绍一下枚举类:枚举类型是java5.0之后开始推出的。考虑这样一种需求,我想设计一个类,它的对象是可数的,并且我想让它的每个对象都唯一的,我还想它的每个对象时不可变的。打个比方说这个类就是,星期week,我该怎么设计呢?

可以使用static final关键字:

package eum;public class week1 {    //定义类成员    public static final week1 MONDAY = new week1(1);    public static final week1 TUESDAY = new week1(2);    public static final week1 WENTHDAY = new week1(3);        private int i;    private  week1(int i) {        this.i=i;    }}

在java1.5之后你可以使用枚举类型:

public enum week2{        //枚举类型的实例        MONDAY,TUESDAY,WENTHDAY;    }

枚举类型的实例在第一次使用的时候被实例化。

枚举类是一种特殊的类,我们在编译时会产生class文件。继承于java.lang.Enum类。定义的时候写出我们需要实例化的对象名称,之后就是写类的定义代码。为了保证数据的唯一性,枚举不能被继承。在实例化时候需要使用Enum.valueOf()方法来实例化对象,一个完整的枚举类型的例子如下:

public class TestEnum {    public enum TestE {        MALE,FEMALE;        public String name;    }    public static void main(String[] args) {        TestE gg1=Enum.valueOf(TestE.class, "MALE");        gg1.name="男";        System.out.println("我是"+gg1+"代表"+gg1.name);                TestE gg2=Enum.valueOf(TestE.class, "MALE");        gg2.name="男主角";        System.out.println("我是"+gg2+"代表"+gg2.name);                        System.out.println("gg1==gg2:"+(gg1.equals(gg2)));        System.out.println("gg1.name==gg2.name:"+(gg1.name==gg2.name));    }}打印的结果是:我是MALE代表男我是MALE代表男主角gg1==gg2:truegg1.name==gg2.name:true

比起我们自己定义的,枚举类有许多好处,一句话,是前辈们设计出来的,确保了每个实例只有一个;而我们自己设计第一种类是有缺陷的,比如序列化的问题。

对于单例模式,可以使用枚举类的设计保护类的安全。

第三个例子:对于不需要实例化的类,私有化其构造器

在一个项目中,我们常常建立一个包专门存放工具类的。比如在Java EE开发中,我们常常需要操作数据库,我们会专门建立一个until包,存放操作数据库的工具,这些类在使用到的时候并不需要实例化多占据计算机资源。此时我们选择定义所有的方法和成员都是静态的。这时可以将类的构造方法私有化,防止其他的使用者滥用。

第四个例子:避免不必要的创建对象

创建多余的对象时很浪费操作时间的,在for循环中会成百倍的浪费系统的时间。因此尽量使用静态方法代替构造器的方法使用方法。对于String常量,有两种定义方式:

String s1=new String("String1");String s1="String1";

尽量使用后面一种定义方式,前者创建了两个对象,后者经创建了一个对象,而且是字符串常量。

Java提供了自动装包的机制,在使用时,需要注意,有时候我们没意识就使用了装包,而创建了大量没有用处的类。

Long s=0L;for(int i=0;i<100;i++){s+=i;}

这段代码,由于自动装包,创建了很多没有实际用处的Long实例。

第五个例子:比较晦涩,垃圾回收,清除Java不要的对象

简单的说是这样的,java垃圾回收是自动的,非常的方便。但是有个需要注意的地方,就是过期应用的情况,它可能造成内存泄露。事情的原因是一个对象只要还有一个引用,那么垃圾回收器就不会回收这个对象。在我们自己设计的堆中,可能先增长,后缩短,如果我们不手动,把那些增长后的有缩短了的,我们不需要的,“对象引用”设置成空的话,这些对象会一直被存在。影响性能。

在我们自己设计内存管理的时候,就是牵扯到引用对象数组的时候需要注意到这个问题。

当然集合已经很好的解决了这个问题。


发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表