Java & Groovy & Scala & Kotlin - 05.数据类型

Overview

本节主要介绍一下四门语言的数据类型

Java 篇

Java 的数据类型主要分为基本数据类型和引用数据类型

基本类型

Java 的基本类型有 int, long, float, double, char, boolean,即以小写字母开头的数据类型。

int x = 2;
float y = 0.1f;
boolean flag = false;

引用数据类型

Java 中除基本数据类型之外的所有数据都属于引用数据类型,并且所有引用数据类型都是 Object 类的子类。

BigDecimal

Java 的基本数值类型及其包装类在进行浮点操作时,很有可能会损失精度。为此,Java 引进了 BigDecimal 类,可以在不损失精度的情况下进行计算。但是不幸的是 Java 的 BigDeciaml 的构造器设计得比较反人类。

System.out.println(2.0 - 1.8);  //0.19999999999999996
System.out.println(new BigDecimal(2.0).subtract(new BigDecimal(1.8)));  //0.1999999999999999555910790149937383830547332763671875
System.out.println(new BigDecimal("2.0").subtract(new BigDecimal("1.8")));  //0.2

从上面的例子可以看到,BigDecimal 有字符串和数值两种构造器,字符串构造器构造的 BigDecimal 才能满足我们的需求,而不是直接使用数值进行构造,基本上用过这个类的人都会踩过这个坑。

类型转换

隐式转换

所谓的隐式转换即无需显示指明需要进行类型转换,由编译器根据变量的类型自动推断。

Java 的隐式转换只发生在使用字面值给变量赋值或者向上转型时

例:

byte b = 1;
int i = b;  //  byte 类型向上转型为 int 类型
char c = 1; //  使用 int 型的字面值 1 为 char 变量赋值

在以上的例子,Java 默认数值字面值为 int 型,只要该数值在 byte 取值范围内,字面值就可以直接赋值给 byte 类型变量。此外由于 int 类型取值范围比 byte 大,所以 byte 变量可以直接赋值给 int 变量,即向上转型。

显式转换

无论是基本类型还是引用类型都是使用 (dataType)value 的语法进行转换。显示转换又称作强制转换,且向下转型时很可能会丢失精度。

int i = (int) 99.98

类型推断

Java 使用关键字 isInstanceof 来判断变量的类型

例:

private static void bar(Object foo) {
    if (foo instanceof String) {
        String fooString = (String) foo;
        System.out.println(fooString.toUpperCase());
    }
}

Object foo = "foo";
bar(foo);

从以上例子可以看到,第二行通过 instanceof 已经知道 fooString 类型了,但是还需要声明一个变量进行强制类型转换,这一做法稍显多余。稍后可以看到 Groovy 的做法要优雅得多。

Groovy 篇

由于 Groovy 就是 Java,所以 Groovy 的数据类型也与 Java 完全一样。但是 Groovy 根据上下文的不同会对自动数据进行包装。

int i = 1
1.toString()

编译以上代码后可以看到,第一行编译后的结果与 Java 完全一样,而第二行由于调用了方法,所以 Groovy 会将其转换为 Integer 类型。这一自动化操作比 Java 的装箱,拆箱操作要更加先进。

由于以上的原因,我们可以认为 Groovy 中一切皆对象。通常来说 Groovy 将数据类型分为静态类型和动态类型。

静态类型

静态类型即声明变量时指定了数据类型,该种变量声明后就不可以再改变数据类型。

int x = 2
float y = 0.1f
boolean flag = false

动态类型

动态类型即使用关键字 def 声明的变量。与静态类型变量不同,动态类型变量在定义后可以任意改变类型。

例:

定义几个动态类型变量

def dx = 2
def dy = 0.1
def dflag = false

改变以上数据的类型

Date staticDate = new Date()
// 静态类型变量
// 无法改变数据类型,会报 'java.lang.Integer' to class 'java.util.Date'
//        staticDate = 2

// 动态类型变量
// 变量可以由 Date 类型转换为 Integer 类型
def dynamicDate = new Date()
dynamicDate = 2

BigDecimal

与 Java 不同,Groovy 中定义一个浮点类型数据实际就是使用 BigDecimal 的字符串构造器定义一个 BigDecimal,所以 Groovy 中不需要做任何额外操作直接就可以做精确的浮点运算。

println(2.0 - 1.8)  //0.2

类型转换

隐式转换

同 Java

显式转换

Groovy 通常使用 toXXX() 这样的方法来实现基本类型的显式转换,语法看起来更加优雅

int i = 99.98.toInteger()
double d = "99.12".toDouble()

需要注意的是 Groovy 并没有提供到 char 类型的转换方法,所以 char 类型还是需要使用 Java 样式的转换方式或者使用以下方式的类型转换:

char c = 99 as char

而对于引用类型的话则转换方式则类似 Java。

类型推断

对于引用类型而言,Groovy 也使用关键字 instanceof 做类型推断,但是 Groovy 也提供了 isXXX() 的语法糖来进行基本类型的推断。

例:

def static bar(foo) {
    if (foo instanceof String) {
        println(foo.toUpperCase())
    }
    if (foo instanceof Double) {
        println(foo.intValue())
    }
    if (foo.isDouble()) {
        println(foo.toDouble())
    }
}

def foo = "foo"
bar(foo)

从以上例子中可以看到,通过 instanceof 进行类型判断以后,变量就可以直接调用其真实类型的方法,无需再声明另一个变量并进行强制类型转换,这一做法相比 Java 方便很多。但是如果使用的是 isXXX() 的语法糖进行类型判断的话则不支持此特性。

Scala 篇

Scala 中并不存在基本类型,所有数据都是对象,且都继承自 Any 类。Scala 数据类型主要分为 AnyValAnyRef,两者都是 Any 的子类。

AnyVal

AnyVal 分为 Int, Long, Float, Double, Boolean, Char, Byte,Unit 几种类型。除了最后一种,其它都可以看做是 Java 上的基本类型的包装类。而 Unit 则相对于 Java 平台上的 Void,即表示没有返回值。

var x: Int = 2
var y: Float = 0.1f
var flag: Boolean = false

AnyRef

AnyRef 是 Scala 中所有引用类的基类,本质上就是 Java 中的 Object 类。

BigDecimal

Scala 中的 BigDecimal 虽然没有 Groovy 那么方便,但是表现也与预期一样

println(BigDecimal(2) - BigDecimal(1.8))

类型转换

隐式转换

类似 Java

显式转换

对于 AnyVal 类型,Scala 科研使用方法进行类型转换

例:

var i:Int = 99.98.toInt
var d:Double = "99.12".toDouble

对于 AnyRef类型,Scala 则使用方法 asInstanceOf[type] 类进行类型转换

例:

val fooString: String = foo.asInstanceOf[String]

类型推断

Scala 使用 isInstanceOf 来进行类型推断,整个过程与 Java 基本一样,需要额外定义变量并显式进行类型转换。

def bar(foo: Any): Unit = {
  if (foo.isInstanceOf[String]) {
    val fooString: String = foo.asInstanceOf[String]
    println(fooString.toUpperCase)
  }
}

Kotlin 篇

Kotlin 中一切皆对象,Any 为所有类的基类。

数据类型

Kotlin 中的所有类型都是引用类型,但是与其它几门语言不一样,Kotlin 中的 Char 类型只属于字符类型,而不属于数值类型。

var x: Int = 2
var y: Float = 0.1f
var flag: Boolean = false

val c: Char = 1 //  错误,Char 不是数值类型

BigDecimal

Kotlin 并没有专门的 BigDecimal 类,需要调用 Java 代码来完成计算

println(BigDecimal("2").subtract(BigDecimal("1.8")));

类型转换

隐式转换

Kotlin 只有使用字面值给变量赋值时的支持自动隐式转换,并且 Kotlin 不支持自动向上转型,这点上比其它几门语言都要严格不少。

var b: Byte = 1

//  错误,不支持自动向上转型
val i: Int = b

显式转换

Kotlin 也使用方法进行内置类型的转换

val i:Int = 99.98.toInt()
"99.12".toDouble()

对于其它类型的数据,Kotlin 使用 as 关键字进行类型转换。

val fooString: String = foo as String

类型推断

Kotlin 使用关键字 is 来进行类型判断,在类型判断后数据会被自动隐式转换为真正的类型,所以可以直接调用该类型的所有方法。在 Kotlin 的文档中称这一特性为 "Smart Cast"。

fun bar(foo: Any) {
    if (foo is String) {
      // 该处发生了 Smart Cast, Any 类型的 foo 在该处被自动转换成了 String 类型
      println(foo.toUpperCase())
    }
}

val foo = "foo"
bar(foo)

Summary

  • 除了 Java 之外,可以认为其它三门语言中一切都是对象
  • 每种语言的数据类型的基类的叫法都有差别:Java(Object), Grooy(Object), Scala(Any), Kotlin(Any)
  • 除了 Java 之外,其它语言都可以使用更优雅的方法调用来完成内置类型的强制类型转换

文章源码见 https://github.com/SidneyXu/JGSK 仓库的 _05_datatype 小节

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容