关于字符串非空判断效率问题
做一个字符串非空的判断,我们经常如下这样写:
if(str == null || "".equals(str)){ //具体操作 }
这是一种很正常的写法,但是如果去比较字符串的长度是否为0的话,效率是更高的。贴个JDK的equals方法的源代码:
public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = count; if (n == anotherString.count) { char v1[] = value; char v2[] = anotherString.value; int i = offset; int j = anotherString.offset; while (n-- != 0) { if (v1[i++] != v2[j++]) return false; } return true; } } return false; }
再来看看str.length()的方法,则是直接返回其大小。两个对比,很明显的length()方法要优化很多。
所以做字符串非空判断尽量写成如下方式:
if(str == null || str.length() == 0){ //具体操作 }
其实也可以用apache-common-lang包下StringUtils.isEmpty(String src);方法判断即可,里面的实现就是用长度来判断的。
经理透露,很多笔试面试题经常都会考这样的问题,如果你用equals来判断,那么在面试官的印象就要大大折扣啦。
Java深克隆(序列化方式)
对于Java的克隆技术,标准的方式是:首先实现Cloneable接口,然后重写clone方法,调用父类clone进行克隆。
介绍另外一种方法,该方法的原理:
利用流将序列化的对象写在流里,因为写在流里面的对象就是原对象的一份拷贝,而原对象还在Java虚拟机里(JVM)里,再从流里面读取出来得到的对象就是得到一份克隆对象。
注意:需要克隆的对象必须实现Serializable接口
接着之前的场景,看下面的例子:
public class User implements Serializable{ private static final long serialVersionUID = 1L; private String userName; private Address address; public User(String userName) { super(); this.userName = userName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } public Object copy() throws IOException, ClassNotFoundException{ //将对象序列化后写在流里,因为写在流里面的对象是一份拷贝, //原对象仍然在JVM里 ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream( bos.toByteArray())); return ois.readObject(); } }
public class Address implements Serializable{ private static final long serialVersionUID = 1L; private String addressName; public Address(String addressName) { super(); this.addressName = addressName; } public String getAddressName() { return addressName; } public void setAddressName(String addressName) { this.addressName = addressName; } }
/** * 测试克隆-深克隆(使用序列化的方式进行深克隆) * 深克隆不但克隆当前的对象,而且还克隆该对象所引用的对象 * @author CST */ public class TestClone { public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException { User chen = new User("CST"); chen.setAddress(new Address("福州")); User liu = (User) chen.copy(); liu.setUserName("LXF"); liu.getAddress().setAddressName("泉州"); System.out.println(chen.getUserName()+"="+chen.getAddress().getAddressName()); } }
输出结果:CST=福州
效果同实现Cloneable接口方式一样
Java克隆技术
前些天,根据需要,加入了克隆技术,学习了下,总结如下:
Java的对象都是引用,当将一个对象赋值给另外一个对象的时候,也就是说指针(当然,java没有指针的概念)同指向同一块内存地址,这个时如果对一个对象进行修改,也必然会修改另外一个对象的值,这明显不是我们想要的,解决这个问题,可以引入克隆技术,我们可以克隆一个对象出来,使得对克隆出来的对象修改不会改变原始对象的值。
克隆分为:浅克隆和深克隆。
浅克隆是指:浅克隆只是克隆当前的对象,不克隆该对象所应用的对象
深克隆是指:深克隆不但克隆当前的对象,而且还克隆该对象所引用的对象
看具体实例:
(模拟场景:用户对象、地址对象、用户对象拥有地址对象)
一、浅克隆
//克隆必须实现Cloneable,调用父类的clone()方法 public class User implements Cloneable{ private String userName; private Address address; public User(String userName) { super(); this.userName = userName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } /* * 克隆当前对象,得到克隆后的对象 * @see java.lang.Object#clone() */ @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } }
//地址对象 public class Address{ private String addressName; public Address(String addressName) { super(); this.addressName = addressName; } public String getAddressName() { return addressName; } public void setAddressName(String addressName) { this.addressName = addressName; } }
/** * 测试克隆-浅克隆 * 浅克隆只是克隆当前的对象,不克隆该对象所应用的对象 * @author CST */ public class TestClone { public static void main(String[] args) throws CloneNotSupportedException { User chen = new User("CST"); chen.setAddress(new Address("福州")); User liu = (User) chen.clone(); liu.setUserName("LXF"); liu.getAddress().setAddressName("泉州"); System.out.println(chen.getUserName()+"="+chen.getAddress().getAddressName()); } }
输出结果:CST=泉州
可以看到,虽然User对象可以单独操作,但是视图去修改User下的Address值,仍然是改变了原始用户下的Address值
二、深克隆:
public class User implements Cloneable{ private String userName; private Address address; public User(String userName) { super(); this.userName = userName; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public Address getAddress() { return address; } public void setAddress(Address address) { this.address = address; } //克隆 @Override public Object clone() throws CloneNotSupportedException { //克隆对象的同时,也克隆user下的应用对象Address User user = (User) super.clone(); Address address = (Address) user.getAddress().clone(); user.setAddress(address); return user; } }
public class Address implements Cloneable{ private String addressName; public Address(String addressName) { super(); this.addressName = addressName; } public String getAddressName() { return addressName; } public void setAddressName(String addressName) { this.addressName = addressName; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
测试类同上,
输出结果:CST=长乐
这样,才是我们想要的结果。无论修改当前对象还是当前对象所包含的对象,都是两个独立的操作,互不影响。