图片 10

toString()

为对象的类型做强制转换是一种非常不好的设计。但在某些情况下,我们没有其他选择。Java自诞生的那一天起,就具备这种功能。

简述在Java中,往往需要把一个类型的变量转换成String
类型。作为菜鸟,有时候我会使用 (String)
data,有时候就使用data.toString(),如果不行还会试试
String.valueOf(data),但始终不是很清楚它们有什么不同。前几天在coding,由于是用gwt-ext编写界面的时候出现了转型错误,所以也没有提示java.lang.ClassCastException的异常,只是提示
gwt exception thrown and not
caught。找了半天才发现原来是因为这个,现特记录一下,以后碰到了也就更清楚些。
看完简述,如果你已完全了解就可以走了,如果也是不太懂可以看看,如果有不对的地方还可以讨论。这也算是开头加上个简述的作用,就是已经了解的人不必重复花时间看了。
toString()方法 先看API 中关于
toString()的描述:返回该对象的字符串表示。通常, toString 
方法会返回一个“以文本方式表示”此对象的字符串。结果应是一个简明但易于读懂的信息表达式。建议所有子类都重写此方法。
Object  类的  toString 
方法返回一个字符串,该字符串由类名(对象是该类的一个实例)、at 标记符“ @
”和此对象哈希码的无符号十六进制表示组成。换句话说,该方法返回一个字符串,它的值等于: 
getClass().getName() + ‘@’ +
Integer.toHexString(hashCode())toString()方法返回的是这个对象的字符串表示,就像是这个对象的名字一样,任何对象都可以有自己的名字,你可以重写其toString()方法,给其赋予任意的名字。但是调用toString()方法的对象不能为
null,否则会抛出异常:java.lang.NullPointerException。String.valueOf()方法上边提到,调用toString()方法的对象不能是null,但接下来这个
String.valueOf()方法却不管这些,其实这个方法也是调用了toString()方法,只不过在调用之前做了点处理,我们来看一下源码:/** 
  * Returns the string representation of theObjectargument.    *    *
@param  obj  anObject.    * @return  if the argument isnull, then a
string equal to    *”null”; otherwise, the value of   
*obj.toString()is returned.    * @see    java.lang.Object#toString() 
  */    public static String valueOf(Object obj) {    return (obj ==
null) ? “null” : obj.toString();   
}不看注释,直接看代码也知道,这个方法就是在调用 toString()
之前判断一下这个对象是不是null,如果不是null,则正常调用其toString()方法,如果是null
的话,则返回 字符串 形式的null。 String.valueOf() 比起直接用 toString()
来说虽然可能会减少报错的机会,但是如果在对比对象值的时候可要小心,要注意如果用
if(String.valueOf(object)==null) 就肯定不行的了。 强制转换
(String)data
这个是初学者最容易出错的,其实每个对象的类型在对象创建的时候已经确定并且不能更改,所谓强制转换也只是使其表面上换成了另一种类型,可以使用其方法对这个对象进行处理。那么可想而知,把物品A
当成物品B 来使用,当A 能能够被当成
B的时候大家都相安无事,你走你的路,我过我的桥,一旦A 不能被当成B
,它不会去自动调用 toString()方法,而是马上就会报错。 例一: Integer
obj1 = new Integer(100);String strVal = (String)obj1;  //Cannot cast
from Integer to String因为obj1 在创建的时候就是 Integer 类型,不能转换成
String 类型,所以在编译期间就会报错Cannot cast from Integer to
String。例二:Object obj2 = new Integer(100);String strVal =
(String)obj2;obj2 虽然本质上是 Integer 类型,但其表面上确是 Object
类型,所以在编译的时候没有报错,但因为 obj2
在创建的时候已经确定了其在本质上 Integer
类型,所以这两行代码在运行时依然会报错,因为 Integer 型不能转换成 String
类型。当然,如果要把 Integer 型转换成 String,可以调用其
toString()方法:Integer.toString(obj1) 或者 String.valueOf(obj1);
对应于其他自定义类型,则调用自己重写的 toString()
方法。此外,因null值可以被强制转换为任何类型,所以(String)null也是合法的。参考资料

Kotlin相比于Java

相比于java 描述
方式更多 类型检查,除了提供了is运算符还提供了!is运算符
更智能 类型检查,会进行变量类型的智能转换
方式更多 类型转换,提供了as运算符和as?运算符
更安全 类型转换,使用as?运算符可以避免转换异常

我认为Java 8在一定程度改善了这项古老的技术。

目标

目标 知识点
掌握 is和!is运算符的使用
掌握 as和as?运算符的使用

静态转型

Java中最常用的转型方式如下:

静态转型

Object obj; // may be an integer
if (obj instanceof Integer) {
    Integer objAsInt = (Integer) obj;
    // do something with 'objAsInt'
}

这里使用了 instanceof
和转型操作符,这些操作符已经融入到语言当中了。对象转换的类型(这个例子中是Integer)必须是在编译期静态确定的,所以我们将这种转型称为静态转型。

如果obj不是Integer,上面的测试就会失败。如果我们以任何方式做类型转换,就会得到一个
ClassCastException 异常。如果obj是null,intanceof
测试会失败,但是转型是可以通过的,因为null可以被任何类型引用。

类型检查(is和!is运算符)

动态转型

有一种不常见的技术,即使用Class的方法,这些方法与上面的操作符的作用是一致的。

动态转换成已知类型

Object obj; // may be an integer
if (Integer.class.isInstance(obj)) {
    Integer objAsInt = Integer.class.cast(obj);
    // do something with 'objAsInt'

注意,这个例子中类型的转换也是在编译期确定的,所以没有必要这么去做。

动态转型

Object obj; // may be an integer
Class<T> type = // may be Integer.class
if (type.isInstance(obj)) {
    T objAsType = type.cast(obj);
    // do something with 'objAsType'
}

因为转换的类型在编译期是不知道,所以我们将这种转型称之为动态转型。

对错误类型和 null 转型的测试结果,与静态转型的结果是完全一致的。

图片 1

回顾Java中instanceof

在Java 中,instanceof
运算符用来在运行时检测对象是否是特定类的一个实例。基本格式如下:

boolean result = someObj instanceof Classs

result,返回结果,true表示是Class的实例,false表示不是Class的实例;

someObj,必选项,任意对象;

Class,必选项,任意对象类;

我们编写一个简单案例,回顾下instanceof运算符的使用,参考代码:

图片 2

针对以上代码,我们注意第18行,我们把object当做字符串使用,这个地方进行了类型的强制转换。

Stream及Optional的转型

is运算符和!is运算符

在Kotlin中,可以使用is运算符用来在运行时检测对象是否是特定类的一个实例。基本格式如下:

图片 3

result,返回结果,true表示是Class的实例,false表示不是Class的实例;

someObj,必选项,任意对象;

Class,必选项,任意对象类;

我们编写一个简单案例,看看is运算符的使用,参考代码:

图片 4

针对以上代码第4行代码,直接使用了String类的length方法。!is是一个与is操作符相对应的操作符,也就是类型不匹配的意思。我们直接参考代码,代码如下:

图片 5

针对以上代码第2行使用了!is运算符。第6行代码,直接使用了String类的length方法。

现在

对 Optional 中的值或 Stream
中的元素转型需要两个步骤:第一步,我们需要过滤掉错误的类型,然后我们需要将其转换为目标类型。

Optional中的转型

Optional<?> obj; // may contain an Integer
Optional<Integer> objAsInt = obj
        .filter(Integer.class::isInstance)
        .map(Integer.class::cast);

我们需要两个步骤来完成转型,这虽然不是什么大问题,但是我感觉还是有一点笨拙和冗余。

智能转换

如果使用了is或者!is运算符,Kotlin就会对类型进行智能转换,不用像Java还需要进行强转类型转换,我们看到之前的代码,obj没有转换为String类型,直接调用了String类的length方法。

总结起来,在if语句、else语句、逻辑或、逻辑与、when表达式都能感受到is和!is运算符带来的智能转换,参考代码:

图片 6

未来(可能)

我建议Class的强制转型方法能返回一个 Optional 或者
Stream。如果传递的对象的类型是正确的,则返回一个包含该对象的Optional或Stream。否则返回的Optional或Stream不包含任何元素。

这些方法的实现比较琐碎:

Class上的新方法

public Optional<T> castIntoOptional(Object obj) {
    if (isInstance(obj))
        return Optional.of((T) obj);
    else
        Optional.empty();
}

public Stream<T> castIntoStream(Object obj) {
    if (isInstance(obj))
        return Stream.of((T) obj);
    else
        Stream.empty();
}

我们可以使用 flatMap 一步完成过滤和强制转换:

FlatMap的实现:

Stream<?> stream; // may contain integers
Stream<Integer> streamOfInts = stream.
        flatMap(Integer.class::castIntoStream);

错误的实例类型或者null引用,在实例测试的时候会失败,所以返回空的
Optional 或 Stream。这种方式永远不会抛出 ClassCastException 异常。

强制转换: as和as?运算符

我们看到,智能转换后,就可以调用某一个类的特定方法。我们还可以通过as和as?运算符强制类型转换,然后调用对应类的对应方法,我们参考如下案例:

图片 7

针对以上代码第3行完成了类型的转换,第4行我们在使用String类的length方法的时候IDE没有提示错误。代码也成功的输出了结果。

     我们对变量a的值稍作改变转换,再看如下结果:

图片 8

针对以上代码第3行完成了类型的转换,第4行我们在使用String类的length方法的时候IDE同样没有提示错误。但是,代码在运行的时候就提示了类型转换异常。甚至,IDE在as关键字的地方,也有相应的提示,参考截图:

图片 9

到这里,我们得到两个结论。第一,Kotlin里面,Int类型不能使用as转换为String类型。第二,使用as运算符进行类型转换,如果转换错误,会抛出异常。

“?.”运算符,是kotlin提供的安全的类型运算符,使用“?.”进行类型转换的时候,如果转换失败,则会返回null,而不会抛出异常,参考代码:

图片 10

针对以上代码第3行进行类型转换的时候使用了安全转换符“?.”。通过运行结果,我们得到两个结论,第一,
Int类型变量不能通过安全转换符“?.”转换为String类。但是Int确实无法转String,所以返回了null。

成本和收益

我们怎么来衡量这些方法是否真正有用呢?

有多少代码真正会使用它们?

对于一个中等水平的开发者来说,它们是否能提高代码的可读性?

是否值得为其节约一行代码?

实现和维护它们的成本是多少?

我对这些问题的回答是:不多,是非常少。所以,这是一个总和趋近于0的游戏,但是,我可以证明虽然收益不多,但却是大于0的。

你怎么认为的呢?你自己会使用这些方法吗?

发表评论

电子邮件地址不会被公开。 必填项已用*标注