这段代码是java中类型转换的一个例子吗?[已关闭]

2q5ifsrm  于 2022-12-21  发布在  Java
关注(0)|答案(2)|浏览(103)

这个问题是由打字错误或无法再重现的问题引起的。虽然类似的问题在这里可能是on-topic,但这个问题的解决方式不太可能帮助未来的读者。
17小时前关门了。
Improve this question

public class main {
    public static void main(String[] args) {

        double num = 324.2;

        System.out.println((int)num);
    }
}

上面的代码是类型转换的一个例子吗?

n3h0vuf2

n3h0vuf21#

非正式地说,是的。Java程序员(包括我自己)经常将其称为类型转换。
但严格地说,Java语言规范(JLS)没有定义,甚至没有在任何地方使用短语“type cast”或“typecast”(您可以通过文本搜索PDF版本的规范来确认这一点,我正在查看最新版本)。
根据JLS,(int) num是 * 强制转换表达式 * 的示例;参见JLS 15.16。该操作在其操作数上执行 * 强制转换 *。

bmp9r5qi

bmp9r5qi2#

所有类型转换都是"类型转换";事实上,"类型转换"作为一个术语并没有出现。
使用这个术语特别危险,几乎不应该使用cast。
问题是,这是"强制转换操作符":(Type) expression;.
它做了5件不同的事情,其中一些是彼此完全无关的。一个真正的枪和祖母的情况。就像这样不同:

int a = 5 + 2; // 7
String b = "hello" + "world" // helloworld

它们都使用+,都被称为"加运算符",但是一个做数字加法,另一个做完全不相关的字符串连接。
对于强制转换操作符也是如此。

原语转换

如果括号中的"type"是一个基元类型,那么java会将表达式视为基元类型(它必须是基元类型,或者是一个装箱类型,在这种情况下,它会将其取消装箱),然后convert。这是**转换操作符可以做的各种事情中唯一的一件。例如:

double x = 5.5;
int y = (int) x;

这个函数把x当作一个基元(它已经是基元了,所以它不做任何事情),然后转换它。double到int的转换去掉了小数点分隔符后面的内容,所以,y现在是5。

类型强制

Object x = "Hello";
String y = (String) x;

这不会转换任何内容。java生成以下代码:
表达式x实际上指向的对象是String的示例或String的某个子类型吗?
如果是-〉完全不做任何事情并继续;就javac而言,表达式(String) xString类型,即使x不是。
如果否-〉,则抛出ClassCastException
在任何情况下,这都不会转换任何内容。例如:

Double d = 5.5;
String x = (String) d;

甚至都不会编译。即使你试图编译它:

Double d = 5.5;
Object o = d;
String x = (String) o;

你会得到一个ClassCastException异常。

类型Assert

List<Object> o = new ArrayList<Object>();
o.add(5.5);
List<String> x = (List<String>) o;

这里括号中唯一值得注意的部分是<String>部分-泛型。这部分只是作为程序员所做的Assert。您告诉javac将表达式(List<String>) o视为List<String>类型,即使o不是。Java什么也不做。此代码在运行时不能失败。即使在上面的情况下,* 是一个非字符串! *-java会盲目地继续。但是,x现在是'堆污染',它的类型是List<String>,但实际上指向一个没有字符串的列表。这意味着稍后如果你这样做:

String y= x.get(0);

你会得到一个ClassCastException,这很奇怪,因为这一行没有强制类型转换!-然而,这就是它的工作原理。通常你应该避免类型Assert。当你写一个类型Assert时,javac会警告你。

显式类型加宽

java中的类型自动加宽例如,如果您有以下方法:

void foo(Object o) {}

你可以用foo("Hello")来调用它。尽管"Hello"是一个String--但是所有的String都是Object,所以String只在需要Object的时候才起作用,你不需要强制转换它。但是,如果你愿意,你可以这样做。通常这是没有意义的,但是如果有多个重载,这就很重要了。假设:

void foo(String o) { System.out.println("String variant"); }
void foo(Object o) { System.out.println("Object variant"); }

你可以调用foo("Hello"),它将打印'String variant'。但是,你也可以写:

foo((Object) "Hello")

这将打印"Object variant"。(重载是静态调度的;它是动态调度的重写)。
这是一个相当重要的代码气味,如果这曾经出现过。

Lambda强制

在java中,闭包/lambda是允许的,但是必须放在一个上下文中,在该上下文中,你可以清楚地知道你想要什么类型,并且该类型必须是Functional Interface类型。例如:

Runnable r = () -> System.out.println("Hello!"):

是合法的java,但这只是因为Runnable r =部分告诉java你希望它是一个RunnableRunnable是一个函数接口,因此没问题)。

Object o = () -> System.out.println("Hello!");

因为Object不是一个函数接口。你可以用一个强制转换来强制它。这个编译:

Object o = (Runnable) () -> System.out.println("Hello!");

你很少需要这个。

关闭通知

除非你在谈论语法本身,否则不要使用"cast"这个词(很少需要谈论这个),而要使用"primitive type convert"、"type coerce"或"type assert"。
注意:最后两种奇特的情况是使用类型强制来实现一个目标,而不是实际强制一个类型。

相关问题