在这里,我们将给大家分享关于任何对象的javatoString的知识,让您更了解任何对象的创建都可以通过界面操作和什么来创建的本质,同时也会涉及到如何更有效地dart–对象的默认stringify,相
在这里,我们将给大家分享关于任何对象的java toString的知识,让您更了解任何对象的创建都可以通过界面操作和什么来创建的本质,同时也会涉及到如何更有效地dart – 对象的默认stringify,相当于Java的toString?、Java String 对 null 对象的容错处理、java String 对象的创建问题、Java String对象的比较的内容。
本文目录一览:- 任何对象的java toString(任何对象的创建都可以通过界面操作和什么来创建)
- dart – 对象的默认stringify,相当于Java的toString?
- Java String 对 null 对象的容错处理
- java String 对象的创建问题
- Java String对象的比较
任何对象的java toString(任何对象的创建都可以通过界面操作和什么来创建)
我有很多数据对象,并且希望能够生成一个String
代表每个对象的对象,而无需为每个对象实现一种toString
方法。
我正在考虑反思以获取领域及其价值。
还有其他想法吗?
谢谢。
答案1
小编典典欢迎您使用雅加达的ToStringBuilder。它有2种模式,一种需要使用API添加您需要的所有字段,另一种是基于反射的:
@Overridepublic String toString() { return ToStringBuilder.reflectionToString(this);}
dart – 对象的默认stringify,相当于Java的toString?
例如:
MyClass myObject = new MyClass(); System.out.println(myObject);
如果覆盖将调用MyClass.toString(),否则将调用它的父级,直到达到java.lang.Object,给出默认的toString.
我发现有点丑陋(完全主观)做:
<span ng-repeat="star in cmp.stars" > {{star.toString()}} </span>
我宁愿这样做:
<span ng-repeat="star in cmp.stars" > {{star}} </span>
并实现我希望它以一种averwritten方法显示的方式.这可能吗?
解决方法
通过覆盖对象上的String toString()方法,显示的值将是此toString()调用的结果.如果在类层次结构中没有定义toString(),则将调用Object的toString()(它将为类MyClass {}返回’MyClass’的实例).
Java String 对 null 对象的容错处理
前言
最近在读《Thinking in Java》,看到这样一段话:
Primitives that are fields in a class are automatically initialized to zero, as noted in the Everything Is an Object chapter. But the object references are initialized to null, and if you try to call methods for any of them, you’ll get an exception-a runtime error. Conveniently, you can still print a null reference without throwing an exception.
大意是:原生类型会被自动初始化为 0,但是对象引用会被初始化为 null,如果你尝试调用该对象的方法,就会抛出空指针异常。通常,你可以打印一个 null 对象而不会抛出异常。
第一句相信大家都会容易理解,这是类型初始化的基础知识,但是第二句就让我很疑惑:为什么打印一个 null 对象不会抛出异常?带着这个疑问,我开始了解惑之旅。下面我将详细阐述我解决这个问题的思路,并且深入 JDK 源码找到问题的答案。
解决问题的过程
可以发现,其实这个问题有几种情况,所以我们分类讨论各种情况,看最后能不能得到答案。
首先,我们把这个问题分解为三个小问题,逐一解决。
第一个问题
直接打印 null 的 String 对象,会得到什么结果?
String s = null;
System.out.print(s);
运行的结果是
null
果然如书上说的没有抛出异常,而是打印了 null
。显然问题的线索在于 print
函数的源码中。我们找到 print
的源码:
public void print(String s) {
if (s == null) {
s = "null";
}
write(s);
}
看到源码才发现原来就只是加了一句判断而已,简单粗暴,可能你对 JDK 的简单实现有点失望了。放心,第一个问题只是开胃菜而已,大餐还在后面。
第二个问题
打印一个 null 的非 String 对象,例如说 Integer:
Integer i = null;
System.out.print(i);
运行的结果不出意料:
null
我们再去看看 print
的源码:
public void print(Object obj) {
write(String.valueOf(obj));
}
有点不一样的了,看来秘密藏在 valueOf
里面。
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
看到这里,我们终于发现了打印 null 对象不会抛出异常的秘密。print
方法对 String 对象和非 String 对象分开进行处理。
- String 对象:直接判断是否为 null,如果为 null 给 null 对象赋值为
"null"
。 - 非 String 对象:通过调用
String.valueOf
方法,如果是 null 对象,就返回"null"
,否则调用对象的toString
方法。
通过上面的处理,可以保证打印 null 对象不会出错。
到这里,本文就应该结束了。
什么?说好的大餐呢?上面还不够塞牙缝呢。
开玩笑啦。下面我们来探讨第三个问题。
第三个问题(隐藏的大餐)
null 对象与字符串拼接会得到什么结果?
String s = null;
s = s + "!";
System.out.print(s);
结果可能你也猜到了:
null!
为什么呢?跟踪代码运行可以发现,这回跟 print
没有什么关系。但是上面的代码就调用了 print
函数,不是它会是谁呢?+
的嫌疑最大,但是 +
又不是函数,我们怎么看到它的源代码?这种情况,唯一的解释就是编译器动了手脚,天网恢恢,疏而不漏,找不到源代码,我们可以去看看编译器生成的字节码。
L0
LINENUMBER 27 L0
ACONST_NULL
ASTORE 1
L1
LINENUMBER 28 L1
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC "!"
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 1
L2
LINENUMBER 29 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
ALOAD 1
INVOKEVIRTUAL java/io/PrintStream.print (Ljava/lang/String;)V
看了上面的字节码是不是一头雾水?这里我们就要扯开话题,来侃侃 +
字符串拼接的原理了。
编译器对字符串相加会进行优化,首先实例化一个 StringBuilder
,然后把相加的字符串按顺序 append
,最后调用 toString
返回一个 String
对象。不信你们看看上面的字节码是不是出现了 StringBuilder
。
String s = "a" + "b";
//等价于
StringBuilder sb = new StringBuilder();
sb.append("a");
sb.append("b");
String s = sb.toString();
再回到我们的问题,现在我们知道秘密在 StringBuilder.append
函数的源码中。
//针对 String 对象
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
//针对非 String 对象
public AbstractStringBuilder append(Object obj) {
return append(String.valueOf(obj));
}
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = ''n'';
value[c++] = ''u'';
value[c++] = ''l'';
value[c++] = ''l'';
count = c;
return this;
}
现在我们恍然大悟,append
函数如果判断对象为 null,就会调用 appendNull
,填充 "null"
。
总结
上面我们讨论了三个问题,由此引出 Java 中 String 对 null 对象的容错处理。上面的例子没有覆盖所有的处理情况,算是抛砖引玉。
如何让程序中的 null 对象在我们的控制之中,是我们编程的时候需要时刻注意的事情。
java String 对象的创建问题
先看看下面的代码
public String makinStrings()
{
String s = "Fred";
s = s + "47";
s = s.substring(2, 5);
s = s.toUpperCase();
return s.toString();
}
问:调用 makinStrings 方法会创建几个 String 对象呢。 答案:4 个
上面的方法有五条语句:现在让我们来一条一条分析一下。
String s = "Fred"; 结论:创建了一个 String 对象
这条语句相当于 String s = new String ("Fred"); 因此,毫无疑问,第一条语句创建了一个 String 对象,我想没有有疑问吧?
s = s + "47"; 结论:未创建 String 对象
这条语句也许很多人认为是创建了 String 对象,我一开始也是这么认为的。但是为了验证我的想法。决定 用点法术恢复这条语句的本来面目。(有很多时候,编译器总是在里面搞一些小动作,javac.exe 也不例外)
现在找到这个程序所生成的.class 文件(假设是 Test.class),找一个反编译工具,我推荐 JAD, 可以 http://www.softpedia.com/progDownload/JAD-Download-85911.html 下载 下载后,有一个 jad.exe,将其路径放到环境变量 path 中(只限 windows)。并在.class 文件的当前路径执行如下的命令:
jad Test
然后大喊一声 “还我本来面目”
会在当前目录下生成一个 Test.jad 文件,打开它,文件内容如下:
public String makinStrings()
{
String s = "Fred";
s = (new StringBuilder(String.valueOf(s))).append("47").toString();
s = s.substring(2, 5);
s = s.toUpperCase();
return s.toString();
}
哈哈,其他的语句都没变,只有第二条变长了,虽然多了个new,但是建立的是StringBuilder对象。原来
这是 java 编译器的优化处理。原则是能不建 String 对象就不建 String 对象。而是用 StringBuilder 对象 加这些字符串连接起来,相当于一个字符串队列。这种方式尤其被使用在循环中,大家可以看看下面的代码: String s = ""; for (int i=0; i < 10000000; i++) s +="aa"; 没有哪位老大认为这是建立了 10000000 个 String 对象吧。但不幸的是,上面的代码虽然没有建立 10000000 个 String 对象 但却建立了 10000000 个 StringBuilder 对象,那是为什么呢,自已用 jad 工具分析一下吧。 正确的写法应该是:
StringBuilder sb = new StringBuilder("");
for(int i=0; i < 10000000; i++)
sb.append(String.valueOf(i));
s = s.substring (2, 5); 结论:创建了一个 String 对象 也许有很多人一开始就认为这条语句是创建了一个 String 对象,那么恭喜你,这条语句确实创建了一个 String 对象 实际上就是 substring 方法创建了一个 String 对象。这也没什么复杂的,自已下一个 JDK 源代码,看看 substring 是如何实现的 就可以知道了。我先说一下吧。先不用管 substring 是如何实现的,反正在 substring 方法返回时使用了一个 new 显式地建立了一个 String 对象 不信自己看看源码。 s = s.toUpperCase (); 结论:创建了一个 String 对象
toUpperCase () 和 substring 方法类似,在返回时也是使用了 new 建立了一个 String 对象。
return s.toString (); 结论:创建 String 对象
toString 方法返回的就是 this,因此,它的返回值就是 s。
这道题还算比较简单,再给大家出一个更复杂一点的,也是关于 String 对象的创建的(只是改了一个原题)。
public String makinStrings()
{
String s = "Fred";
s = s + "Iloveyou.".substring(1).toLowerCase();
s = s.substring(0);
s = s.substring(0,1).toUpperCase();
return s.toString();
}
先公布答案吧,上述代码也创建了 4 个 String 对象,哈哈!
为什么呢?
要想知道为什么,先得弄清楚 substring、toLowerCase 和 toUpperCase 什么时候创建 String 对象,什么时候不创建对象。
substring 方法在截取的子字符串长度等于原字符串时,直接返回原字符串。并不创建新的 String 对象。
toLowerCase 方法在字符串中更本没有需要转换的大写字母时直接返回原字符串,如 "abcd".toLowerCase () 直接返回 abcd,并不创建新的 String 对象
toUpperCase 方法和 toLowerCase 类似。"ABCD".toUpperCase () 直接返回 ABCD。
知道了这个,上面的代码就非常清楚了。
public String makinStrings()
{
String s = "Fred"; // 创建一个String对象
s = s + "Iloveyou.".substring(1).toLowerCase(); // substring(1)创建一个String对象,由于toLowerCase()转换的字符串是"loveyou.",没有大写字母,因此,它不创建新的String对象
s = s.substring(0); // 由于substring(0)截获的是s本身,因此,这条语句不创建新的String对象
s = s.substring(0,1).toUpperCase(); // substring(0,1)创建了一个String对象,但由于substring(0,1)的结果是"F",为一个大写字母,因此,toUpperCase直接返回"F"本身。
return s.toString();
}
Java String对象的比较
package test;
public class Stringdemo1 { private static String getString() { return "AB"; } public static void main(String[] args) { /* 编译优化 String对象比较: 1.单独使用“ ”引号创建的字符串都是直接量,编译期就已经确定存储到常量池中 2.使用new String (“”)创建的对象会存储到堆内存中,是运行期才创建的。 3.使用只包含直接量的字符串连接符 如“aa”+“bb” 创建的也是直接量 编译期就能确定 ,已经确定存储到常量池中(str2)和(str3) 4.使用包含String 直接量(无final修饰符)的字符串表达式(如 “aa”+s1)创建的对象时运行才创建 存储在堆中; 通过变量/调用去连接字符串,都只能在运行期间才能确定变量的值和方法的返回值 不存在编译优化操作。 * */ String string1 = "ABCD"; String string2 = "A"+"B"+"C"+"D"; String string3 = "AB"+"CD"; String string4 = new String("ABCD"); String temp = "AB"; String string5 = temp +"CD"; String string6 = getString()+"CD";
System.out.println(string1==string2); //true
System.out.println(string1==string3); //true
System.out.println(string1==string4); //false
System.out.println(string1==string5); //false
System.out.println(string1==string6); //false
}
}
关于任何对象的java toString和任何对象的创建都可以通过界面操作和什么来创建的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于dart – 对象的默认stringify,相当于Java的toString?、Java String 对 null 对象的容错处理、java String 对象的创建问题、Java String对象的比较等相关内容,可以在本站寻找。
本文标签: