可空类型
在Kotlin中,我们可以在任何类型后面加上“?
”,比如“Int?
”,实际上等同于“Int? = Int or null
”。
通过合理的使用,不仅能够简化很多判空代码,还能够有效避免空指针异常。
注意:由于null
只能被存储在 Java 的引用类型的变量中,所以在 Kotlin 中基本数据的可空版本都会使用该类型的包装形式 。同样,如果你用基本数据类型作为泛型类的类型参数,Kotlin同样会使用该类型的包装形式。(即可空类型会自动装箱 )
Java中对于null
的一些解决方案:
函数内对于无效值,可以抛异常处理。
采用@NotNull
/@Nullable
标注。
使用专门的Optional
对象对可能为null
的变量进行装箱。
可空类型相关的安全操作符
安全的调用 ?.
s. student? . glasses? . degreeOfMyopia
Elvis操作符 ?:
val result = student. glasses? . degreeOfMyopia ?: - 1
又称合并运算符
非空断言 !!
val result = student!! . glasses
类型检查
在Kotlin中,我们可以用“is
”来判断。
if ( obj is String) {
print ( obj. length)
}
if ( obj ! is String) {
print ( "Not a String" )
} else {
print ( obj. length)
}
when ( obj) {
is String -> print ( obj. length)
! is String -> print ( "Not a String" )
}
类型智能转换
Smart Casts 可以将一个变量的类型转变为另一种类型,它是隐式完成的。
val stu: Any = Student ( Glasses ( 189.00 ) )
if ( stu is Student) println ( stu. glasses)
对于可空类型,我们可以使用 Smart Casts:
val stu: Student = Student ( Glasses ( 189.00 ) )
if ( stu. glasses != null ) println ( stu. glasses. degreeOfMyopia)
我们将这个例子反编译成Java,核心代码如下
. . .
Intrinsics . checkParameterlsNotNull ( args, "args" ) ;
Student stu = new Student ( new Glasses ( 189.0D ) ) ;
if ( stu instanceof Student ) {
Glasses var2 = ( ( Student ) stu) . getGlasses ( ) ;
System . out. println ( var2) ;
}
. . .
我们可以看到,这与我们写的Java版本一致,这其实是Kotlin的编译器帮我们做出了转换。
根据官方文档介绍:当且仅当Kotlin的编译器确定在类型检查后该变量不会再改变,才会产生SmartCasts。
利用这点,我们能确保多线程的应用足够安全。举个例子:
class Kot {
var stu: Student? = getStu ( )
fun dealStu ( ) {
if ( stu != null ) {
print ( stu. glasses)
}
}
}
上述代码中,我们将stu
声明为引用可空类型变量,这意味着在判断 stu != null
之后,stu
在其他线程中还是会被修改的,所以被编译器无情地拒绝了。
将var
改为val
就不会存在这样的问题,引用不可变能够确保程序运行不产生额外的副作用。你也许会觉得这样写不够优雅,我们可以用let
函数来简化⼀下:
class Kot {
var stu: Student? = getStu ( )
fun dealStu ( ) {
stu? . let { print ( it. glasses) }
}
}
这样就会满足 Smart Casts 的条件,就不会被拒绝编译。
在实际开发中,我们并不总能满足 Smart Casts 的条件。并且 Smart Casts 有时会缺乏语义,并不适用于所有场景。
当类型需要强制转换时,我们可以利用“ as
” 操作符来实现。
class Kot {
val stu: Student? = getStu ( ) as Student?
fun dealStu ( ) {
if ( stu != null ) {
print ( stu. classes)
}
}
}
由于val
只允许赋值一次,这样,我们在外部已经确定了stu
的类型,当stu
不为空时,在dealStu
方法里就可以成功调用stu
的参数。
注意:
这里stu
变量是在dealStu()
方法的外面,必须使用val
生声明,否则如果是var
,仍然可能有线程安全问题所以也会被拒绝编译。
如果stu
变量是放在dealStu()
方法的里面,那么可以使用var
, 因为是方法本地局部变量,会被线程独占,此时也满足 Smart Casts 的条件。
因为getStu
可能为空,如果我们将其转换类型改为 Student
:
val stu: Student? = getStu ( ) as Student
则会抛出类型转换失败的异常,因为它不是可空的。所以,我们通常称之为“ 不安全” 的类型转换。
那是否有安全版本的转换呢?除了上述写法外,Kotlin还提供了操作符“ as?
”,我们可以这样改写:
val stu: Student? = getStu ( ) as ? Student
这时,如果stu
为空将不会抛出异常,而是返回转换结果null
。
Any:非空类型的根类型
与 Object
作为 Java 类层级结构的顶层类似,Any
类型是 Kotlin 中所有非空类型 (如String
、Int
)的超类:
与 Java 不同的是,Kotlin 不区分“原始类型”(primitivetype)和其他的类型,它们都是同一类型层级结构的一部分。
如果定义了一个没有指定父类型的类型,则该类型将是Any
的直接子类型。如:
class Animal ( val weight: Double)
如果你为定义的类型指定了父类型,则该父类型将是新类型的直接父类型,但是新类型的最终根类型为Any
。
另外,Kotlin 把 Java 方法参数和返回类型中用到的 Object
类型看作 Any
(更确切地说是当作“平台类型”)。当在 Kotlin 函数中使用 Any
时,它会被编译成 Java 字节码中的 Object
。
什么是平台类型?
平台类型本质上就是 Kotlin 不知道可空性信息的类型,所有 Java 引用类型在 Kotlin 中都表现为平台类型。当在 Kotlin 中处理平台类型的值的时候,它既可以被当作可空类型来处理,也可以被当作非空类型来操作。
平台类型的引入是 Kotlin 兼容 Java 时的一种权衡设计。试想下,如果所有来自 Java 的值都被看成非空,那么就容易写出比较危险的代码。反之,如果 Java 中的值都强制当作可空,则会导致大量的 null
检查。综合考量,平台类型是一种折中的设计方案。
Any?:所有类型的根类型
如果说Any
是所有非空类型的根类型,那么 Any?
才是所有类型(可空和非空类型)的根类型。 Any
与 Any?
看起来没有继承关系,然而在我们需要用 Any?
类型值的地方,显然可以传入一个类型为Any
的值,这在编译上不会产生问题。比如在 Kotlin 中 Int
是 Number
的子类:
fun printNum ( num : Number) {
println ( num)
}
val n : Int = 1
printNum ( n)
反之却不然,比如一个参数类型为Any
的函数,我们传入符合 Any?
类型的null
值,就会出现如下的错误:
error: null can not be a value of a non- null type Any
Nothing 与 Nothing?
在 Kotlin 类型层级结构的最底层是 Nothing
类型。
Nothing
是没有实例的类型。Nothing
类型的表达式不会产生任何值。需要注意的是,任何返回值为Nothing
的表达式之后的语句都是无法执行的。你是不是感觉这有点像return
或者break
的作用?没错,Kotlin 中 return
、throw
等(流程控制中与跳转相关的表达式)返回值都为Nothing
。
Nothing?
是 Nothing
的父类型,其实,它只能包含一个值:null
,本质上与null
没有区别。所以我们可以使用null
作为任何可空类型的值。
自动装箱与拆箱
我们发现,Kotlin 中并没有 int
、float
、double
、long
这样的原始类型,取而代之的是它们对应的引用类型包装类Int
、Float
、Double
、Long
。
除了以上代表数值的类型,还有布尔(Boolean
)、字符(Char
)、字符串(String
)及数组(Array
)。这让 Kotlin 比起 Java 来更加接近纯面向对象的设计——一切皆对象。
但这么说其实也是不够严谨的。以Int
为例,虽然它可以像Integer
一样提供额外的操作函数,但这两个类型在底层实现上存在差异。Kotlin 中的 Int
在 JVM 中实际以 int
存储(对应字节码类型为I
)但是,作为一个“ 包装类型”,编译后应该装箱才对,难道,Kotlin 不会自动装箱?
我们可以简单地认为:
Kotlin中的 Int
类型等同于 int
;
Kotlin中的 Int?
等同于 Integer
。
Int
作为一种小技巧,让Int
看起来是引用类型,这在语法上让 Kotlin 更接近纯面向对象语言。
数组类型
val funList = arrayOf ( )
val funList = arrayOf ( n1, n2, n3, .. . , nt)
Kotlin中 Array
并不是一种原生的数据结构,而是一种Array
类,甚至我们可以将 Kotlin 中的Array
视作集合类的一部分。
由于 Smart Casts,编译器能够隐式推断出funList
元素类型。当然,我们也可以手动指定类型
val funList = arrayOf< T> ( n1, n2, n3.. . , nt)
在 Kotlin 中,还为原始类型额外引入了一些实用的类:IntArray
、CharArray
、ShortArray
等,分别对应 Java 中的int[]
、char[]
、short[]
等。
val x = intArrayOf ( 1 , 2 , 3 )
注意:IntArray
等并不是Array
的子类,所以用两者创建的相同值的对象,并不是相同对象。
由于 Kotlin 对原始类型有特殊的优化(主要体现在避免了自动装箱带来的开销),所以我们建议优先使用原始类型数组。
泛型
class SmartList< T> : ArrayList< T> ( ) {
fun find ( t: T) : T? {
val index = super . indexOf ( t)
return if ( index >= 0 ) super . get ( index) else null
}
fun main ( args: Array< String> ) {
val smartList = SmartList< String> ( )
smartList. add ( "one" )
println ( smartList. find ( "one" ) )
println ( smartList. find ( "two" ) . isNullOrEmpty ( ) )
}
}
由于扩展函数支持泛型,可以利用扩展函数实现上面的功能:
fun < T> ArrayList< T> . find ( t: T) : T? {
val index = this . indexOf ( t)
return if ( index >= 0 ) this . get ( index) else null
}
fun main ( args: Array< String> ) {
val arrayList = ArrayList< String> ( )
arrayList. add ( "one" )
println ( arrayList. find ( "one" ) )
println ( arrayList. find ( "two" ) . isNullOrEmpty ( ) )
}
类型约束:设定类型上界
class FruitPlate< T : Fruit> ( val t: T)
class Noodles ( weight: Double)
val applePlate = FruitPlate< Apple> ( Apple ( 100.0 ) )
val applePlate = FruitPlate ( Apple ( 100.0 ) )
val noodlesPlate = FruitPlate< Noodles> ( Noodles ( 200.0 ) )
支持可空T
类型:
class FruitPlate< T: Fruit? > ( val t: T)
val fruitPlate = FruitPlate ( null )
多个泛型条件约束:
interface Ground { }
class Watermelon ( weight: Double) : Fruit ( weight) , Ground
fun < T> cut ( t: T) where T : Fruit, T : Ground {
print ( "You can cut me." )
}
cut ( Watermelon ( 3.0 ) )
cut ( Apple ( 2.0 ) )
我们可以通过where
关键字来实现这种需求,它可以实现对泛型参数类型添加多个约束条件,比如这个例子中要求被切的东西是一种水果,而且必须是长在地上的水果。
Java 为什么无法声明一个泛型数组
我们先来看一个简单的例子,Apple
是Fruit
的子类,思考下Apple[]
和Fruit[]
,以及List
和List
是什么关系呢?
Apple [ ] appleArray = new Apple [ 10 ] ;
Fruit [ ] fruitArray = appleArray;
fruitArray[ 0 ] = new Banana ( 0.5 ) ;
List < Apple > appleList = new ArrayList < Apple > ( ) ;
List < Fruit > fruitList = appleList;
我们发现一个奇怪的现象,Apple[]
类型的值可以赋值给Fruit[]
类型的值,而且还可以将一个Banana
对象添加到fruitArray
,编译器能通过。作为对比,List
类型的值则在一开始就禁止被赋值为List
类型的值,这其中到底有什么不同呢?
其实这里涉及一个关键点,数组是协变的,而List
是不变的 。简单来说,就是 Object[]
是所有对象数组的父类,而 List 却不是 List
的父类。
Java 中的泛型是类型擦除的,可以看作伪泛型 ,简单来说,就是你无法在程序运行时获取到一个对象的具体类型 。
我们可以用以下代码来对比一下List
和数组:
System . out. println ( appleArray. getClass ( ) ) ;
System . out. println ( appleList. getClass ( ) ) ;
运行结果:
class [ Ljavat. Apple ;
class java. util. ArrayList
数组在运行时是可以获取自身的类型,而List
在运行时只知道自己是一个List
,而无法获取泛型参数的类型。
而 Java 数组是协变 的,也就是说任意的类 A 和 B ,若 A 是 B 的父类,则 A[] 也是 B[] 的父类。但是假如给数组加入泛型后,将无法满足数组协变的原则,因为在运行时无法知道数组的类型。
Kotlin 中的泛型机制与 Java 中是一样的,所以上面的特性在 Kotlin 中同样存在。
比如通过下面的方式同样无法获取列表的类型:
val appleList = ArrayList< Apple> ( )
println ( appleList. javaClass)
但不同的是,Kotlin 中的数组是支持泛型的,当然也不再协变 ,也就是说你不能将任意一个对象数组赋值给 Array
或者 Array
。
val appleArray = arrayOfNulls< Apple> ( 3 )
val anyArray: Array< Any? > = appleArray
获取泛型参数类型
如何在运行时获取泛型类型的参数信息?可以利用匿名内部类 。
val list1 = ArrayList< String> ( )
val list2 = object : ArrayList< String> ( ) { }
println ( list1. javaClass. genericSuperclass)
println ( list2. javaClass. genericSuperclass)
结果:
java. util. AbstractList< E>
java. util. ArrayList< java. lang. String>
那么,为什么使用匿名内部类的这种方式能够在运行时获取泛型参数的类型呢?
其实泛型类型擦除并不是真的将全部的类型信息都擦除,还是会将类型信息放在对应class
的常量池 中的。
import java. lang. reflect. ParameterizedType
import java. lang. reflect. Type
open class GenericsToken< T> {
var type: Type = Any:: class . java
init {
val superClass = this . javaClass. genericSuperclass
type = ( superClass as ParameterizedType) . actualTypeArguments[ 0 ]
}
fun main ( ) {
val gt = object : GenericsToken< Map< String, String> > ( ) { }
println ( gt. type)
}
}
结果:
java. util. Map< java. lang. String, ? extends java. lang. String>
匿名内部类在初始化的时候就会绑定父类或父接口的相应信息 ,这样就能通过获取父类或父接口的泛型类型信息来实现我们的需求 。
你可以利用这样一个类来获取任何泛型的类型,我们常用的Gson
也是使用了相同的设计。(TypeToken)
private Type getTypeTokenTypeArgument ( ) {
Type superclass = getClass ( ) . getGenericSuperclass ( ) ;
if ( superclass instanceof ParameterizedType) {
ParameterizedType parameterized = ( ParameterizedType) superclass;
if ( parameterized. getRawType ( ) == TypeToken. class) {
return $Gson$Types. canonicalize ( parameterized. getActualTypeArguments ( ) [ 0 ] ) ;
}
}
.. .
}
比如,我们在 Kotlin 中可以这样使用Gson
来进行泛型类的反序列化:
val json = .. .
val rType = object : TypeToken< List< String> > ( ) { } . type
val stringList = Gson ( ) . fromJson< List< String> > ( json, rType)
使用内联函数获取泛型
在 Kotlin 中除了用这种方式来获取泛型参数类型以外,还有另外一种方式,那就是内联函数 。
Kotlin中的内联函数在编译的时候编译器便会将相应函数的字节码插入调用的地方,也就是说,参数类型也会被插入字节码中,我们就可以获取参数的类型了。
inline fun < reified T> getType ( ) {
return T:: class . java
}
使用内联函数获取泛型的参数类型非常简单,只需加上reified
关键词即可。这里的意思相当于,在编译的会将具体的类型插入相应的字节码中,那么我们就能在运行时获取到对应参数的类型了。所以,我们可以在 Kotlin 中改进 Gson
的使用方式:
inline fun < reified T: Any> Gson. fromJson ( json: String) : T {
return Gson ( ) . fromJson ( json, T:: class . java)
}
fun main ( ) {
val json = "..."
val stringList = Gson ( ) . fromJson< List< String> > ( json)
}
这里利用了 Kotlin 的扩展特性对 Gson
进行了功能扩展,在不改变原有类结构的情况下新增方法,很多场景用 Kotlin 来实现便会变得更加优雅。
另外需要注意的一点是,Java 并不支持主动指定一个函数是否是内联函数,所以在 Kotlin 中声明的普通内联函数可以在Java中调用,因为它会被当作一个常规函数;而用reified
来实例化的参数类型的内联函数则不能在 Java 中调用,因为它永远是需要内联的 。
泛型中的协变
在 Java 中不支持将List
赋值给List,如果支持这种行为的话,那么它将会和数组支持泛型一样,不再保证类型安全。
List < String > stringList = new ArrayList < String > ( ) ;
List < Object > objList = stringList;
objList. add ( Integer . valueOf ( 1 ) ) ;
String str = stringList. get ( 0 ) ;
但是在 Kotlin 中却支持这样做:
val stringList: List< String> = ArrayList< String> ( )
val anyList: List< Any> = stringList
关键在于这两个List
并不是同一种类型 。我们分别来看一下两种List
的定义:
public interface List < E > extends Collection < E > {
. . .
}
public interface List< out E> : Collection< E> {
.. .
}
虽然都叫List
,也同样支持泛型,但是 Kotlin 的 List
定义的泛型参数前面多了一个out
关键词。普通方式定义的泛型是不变 的,简单来说就是不管类型 A
和类型 B
是什么关系Generic
与Generic
(其中Generic
代表泛型类)都没有任何关系 。比如,在 Java 中 String
是 Oject
的子类型,但 List
并不是 List 的子类型,在 Kotlin 中泛型的原理也是一样的。
如果在定义的泛型类和泛型方法的泛型参数前面加上out
关键词,说明这个泛型类及泛型方法是协变 ,简单来说如果类型 A
是类型 B
的子类型,那么 Generic
也是 Generic
的子类型 ,比如在 Kotlin 中 String
是 Any
的子类型,那么List
也是List
的子类型,所以List
可以赋值给List
。
但是我们上面说过,如果允许这种行为,将会出现类型不安全的问题。那么Kotlin是如何解决这个问题的?我们来看一个例子:
val stringList: MutableList< String> = ArrayList< String> ( )
stringList. add ( "kotlin" )
这又是什么情况,往一个List
中插入一个对象竟然不允许,难道这个List
只能看看?确实是这样的,因为这个List
支持协变,那么它将无法添加元素,只能从里面读取内容。(即只读 的List
)
这点我们查阅List
的源码也可以发现:List
中本来就没有定义add
方法,也没有remove
及replace
等方法,也就是说这个List
一旦创建就不能再被修改,这便是将泛型声明为协变需要付出的代价。
那么为什么泛型协变会有这个限制呢?同样我们用反证法来看这个问题,如果允许向这个List
插入新对象,会发生什么?我们来看一个例子:
val stringList: List< String> = ArrayList< String> ( )
val anyList: List< Any> = stringList
anyList. add ( 1 )
val str: String = anyList[ 0 ]
从上面的例子可以看出,假如支持协变的List
允许插入新对象,那么它就不再是类型安全的 了,也就违背了泛型的初衷。
所以我们可以得出结论:支持协变的List
只可以读取,而不可以添加 。其实从out
这个关键词也可以看出,out
就是出的意思,可以理解为List
是一个只读列表 。
在 Java 中也可以声明泛型协变,用通配符及泛型上界来实现协变:
,其中T
可以是任意类。比如在 Java 中声明一个协变的List
:
List < ? extends Animal > list = new ArrayList < Dog > ( ) ;
但泛型协变实现起来非常别扭,这也是 Java 泛型一直被诟病的原因。很庆幸,Kotlin 改进了它,使我们能用简洁的方式来对泛型进行不同的声明。
另外需要注意的一点的是:通常情况下,若一个泛型类Generic
支持协变,那么它里面的方法的参数类型不能使用 T
类型,因为一个方法的参数不允许传入参数父类型的对象,因为那样可能导致错误。
class Generic< out T> {
fun funs1 ( a: T) {
}
fun < E> fun2 ( a: E) {
}
fun < E> fun3 ( ) : T {
}
}
什么是逆变?
你说协变我还好理解,毕竟原来是父子,支持泛型协变后的泛型类也还是父子关系。但是反过来又是一个什么情 况? 比如 Double
是 Number
的子类型,反过来Generic
却是Generic
的父类型?那么到底有没有这种场景呢?
一个支持逆变的 Comparator
我们来思考一个问题,假设现在需要对一个MutableList
进行排序,利用其sortWith
方法,我们需要传入一个比较器,所以可以这么做:
val doubleComparator = Comparator< Double> { d1, d2 ->
d1. compareTo ( d2)
}
val doubleList = mutableListOf ( 2.0 , 3.0 )
doubleList. sortWith ( doubleComparator)
暂时来看, 没有什么问题。 但是现在我们又需要对MutableList
、MutableList
等进行排序,那么我们是不是又需要定义intComparator
、longComparator
等呢?现在看来这并不是一种好的解决方法。那么试想一下可不可以定义一个比较器,给这些列表使用。
我们知道,这些数字类有一个共同的父类Number
,那么Number
类型的比较器是否代替它的子类比较器?比如:
val numberComparator = Comparator< Number> { n1, n2 ->
n1. toDouble ( ) . compareTo ( n2. toDouble ( ) )
}
val doubleList = mutableListOf ( 2.0 , 3.0 )
doubleList. sortWith ( numberComparator)
val intList = mutableListOf ( 1 , 2 )
intList. sortWith ( numberComparator)
编译通过,验证了我们的猜想。
那么为什么numberComparator
可以代替 doubleComparator
、 intComparator
呢? 我们来看一下sortWith
方法的定义:
public fun < T> MutableList< T> . sortWith ( comparator: Comparator< in T> ) : Unit
if ( size > 1 ) java. util. Collections. sort ( this , comparator)
}
这里我们又发现了一个关键词 in
,跟out
一样,它也使泛型有了另一个特性,那就是逆变 。简单来说,假如类型 A
是类型 B
的子类型,那么 Generic
反过来是 Generic
的子类型 ,所以我们就可以将一个numberComparator
作为doubleComparator
传入。那么将泛型参数声明为逆变会不会有什么限制呢?
前面我们说过,用out
关键字声明的泛型参数类型将不能作为方法的参数类型,但可以作为方法的返回值类型,而in
刚好相反。比如声明以下一个列表:
class WriteableList< in T> {
fun add ( a: T) : Int {
}
fun get ( index: T) : T {
}
fun get ( index: T) : Any {
}
}
我们不能将泛型参数类型当作方法返回值的类型,但是作为方法的输入参数类型没有任何限制,其实从in
这个关键词也可以看出,in
就是入的意思,可以理解为消费内容,所以我们可以将这个列表看作一个可写、但可读功能受限的列表,获取的值只能为Any
类型。在Java中使用
可以达到相同效果。
如何使用 in 和 out
in
和out
是一个对立面,其中in
代表泛型参数类型逆变,out
代表泛型参数类型协变。从字面意思上也可以理解,in
代表着输入,而out
代表着输出。但同时它们又与泛型不变相对立,统称为型变 ,而且它们可以用不同方式使用。
比如:
public interface List< out E> : Collection< E> { }
这种方式是在声明处型变,另外还可以在使用处型变,比如前面例子中sortWith
方法。
假设现在有个需求,需要将数据从一个Double
数组拷贝到另一个Double
数组,我们该怎么实现呢?
一开始我们可能会这么做:
fun copy ( dest: Array< Double> , src: Array< Double> ) {
if ( dest. size < src. size) {
throw IndexOutOfBoundsException ( )
} else {
src. forEachIndexed { index, value -> dest[ index] = src[ index] }
}
}
var dest = arrayOfNulls< Double> ( 3 )
val src = arrayOf< Double> ( 1.0 , 2.0 , 3.0 )
copy ( dest, src)
但是学过泛型后的你一定不会这么做了,因为假如替换成Int
类型的列表,是不是又得写一个copy
方法?所以我们可以对其进一步抽象:
fun < T> copy ( dest: Array< T> , src: Array< T> ) {
if ( dest. size < src. size) {
throw IndexOutOfBoundsException ( )
} else {
src. forEachIndexed { index, value -> dest[ index] = src[ index] }
}
}
var destDouble = arrayOfNulls< Double> ( 3 )
val srcDouble = arrayOf< Double> ( 1.0 , 2.0 , 3.0 )
copy ( destDouble, srcDouble)
var destInt = arrayOfNulls< Int> ( 3 )
val srcInt = arrayOf< Int> ( 1 , 2 , 3 )
copy ( destInt, srcInt)
那么这种方式有没有什么局限呢?我们发现,使用copy
方法必须是同一种类型,那么假如我们想把Array
拷贝到Array
中将不允许。
这时候我们就可以利用泛型型变了。
fun < T> copy ( dest: Array< in T> , src: Array< out T> ) {
if ( dest. size < src. size) {
throw IndexOutOfBoundsException ( )
} else {
src. forEachIndexed { index, value -> dest[ index] = src[ index] }
}
}
fun test ( ) {
val dest = arrayOfNulls< Number> ( 3 )
val src = arrayOf< Double> ( 1.0 , 2.0 , 3.0 )
copy ( dest, src)
}
in
是声明在dest
数组上,而out
是声明在src
数组上,所以dest
可以接收T
类型的父类型的Array
,src
可以接收T
类型的子类型的Array
。当然这里的T
要到编译的时候才能确定。
Kotlin 与 Java 的型变比较:
型变类型
Kotlin 实现方式
Java 实现方式
含义
协变
消费者,只能读取不能添加
逆变
生产者,只能添加,读取受限
不变
既可以添加,也可以读取
如果你对泛型参数的类型不感兴趣,那么你可以使用类型通配符来代替泛型参数。前面已经接触过 Java 中的泛型类型通配符“?
”,而在 Kotlin 中则用“*
”来表示类型通配符。比如:
val list: MutableList< * > = mutableListOf ( 1 , "kotlin" )
list. add ( 2.0 )
这个列表竟然不能添加,不是说好是通配吗?按道理应该可以添加任意元素。
其实不然,MutableList<*>
与MutableList
不是同一种列表,后者可以添加任意元素,而前者只是通配某一种类型,但是编译器却不知道这是一种什么类型,所以它不允许向这个列表中添加元素,因为这样会导致类型不安全。
前面所说的协变也是不能添加元素,那么它们两者之间有什么关系呢?其实通配符只是一种语法糖,背后上也是用协变 来实现的。所以MutableList<*>
本质上就是MutableList
,使用通配符与协变有着一样的特性。
你可能感兴趣的:(kotlin,kotlin,可空类型,平台类型,自动装箱,数组类型,泛型,协变与逆变)
储能变流器硬件工程师能力提升路径
DOMINICHZL
硬件 能源 硬件工程
储能变流器(PCS,PowerConversionSystem)作为储能系统的核心部件,其硬件设计涉及电力电子、控制理论、热管理、电磁兼容(EMC)等多领域技术。以下是储能变流器行业硬件工程师需要具备的核心能力,以及技术提升的路径建议:一、储能变流器硬件工程师的核心能力电力电子基础能力拓扑设计与分析:熟悉Boost/Buck、双向DC-DC、三相逆变器、LLC谐振变换器等拓扑结构,并能根据效率、成
提升空间卫生,稀土抗菌剂让铺地材料更健康
金士镧新材料有限公司
全文检索 科技 生活 安全
一、稀土元素的抗菌特性稀土元素包括镧系元素及其他一些具有特定化学性质的元素(如钪、钇等),这些元素具有较强的催化性和化学活性,能有效抑制细菌的生长和繁殖。稀土元素尤其是铈、钕、钬、钇等,因其在抗菌方面的特殊作用,能够有效杀灭多种常见的细菌和真菌,并能防止细菌的耐药性产生。稀土抗菌剂的抗菌抑菌机理有四个层面:1.稀土化合物与细菌表面静电结合,造成直接的杀灭;2.基于稀土的光催化半导体特性,通过光生氧
针对AF调试过程中PD多窗机制是如何打分的
爱写BUG的长歌
人工智能 计算机视觉 算法
在AF(自动对焦)调试中,PD多窗机制(PhaseDetectionMulti-Window)是提升相位对焦精度和鲁棒性的关键技术,其核心是通过在画面中划分多个相位检测窗口,分别计算各窗口的相位差(PhaseDifference)并进行综合评分,最终选择最优对焦位置。以下是其打分机制的核心逻辑和调试要点:1.多窗口布局与权重分配窗口划分根据Sensor的PDAF像素分布,将画面划分为多个区域(例如
基于Java的智能家居设计:模块化智能插座的设计与实现
AGI大模型与大数据研究院
DeepSeek R1 & 大数据AI人工智能 java python javascript kotlin golang 架构 人工智能
智能家居,Java,模块化设计,智能插座,物联网,MQTT,RESTfulAPI1.背景介绍智能家居已成为现代生活的重要趋势,它通过将各种智能设备连接到网络,实现对家居环境的自动化控制和远程管理。智能插座作为智能家居的基础设备之一,能够远程控制电器开关,监测电器功耗,并根据用户需求实现定时开关等功能。传统的智能插座往往采用单片机或嵌入式系统,功能相对单一,难以扩展和升级。随着物联网技术的快速发展,
决策树的核心思想
code 旭
AI人工智能学习 决策树 算法 机器学习
一、决策树的核心思想本质:通过特征判断对数据集递归划分,形成树形结构。目标:生成一组“若-则”规则,使数据划分到叶子节点时尽可能纯净。关键流程:特征选择:选择最佳分裂特征(如信息增益最大)。节点分裂:根据特征取值划分子节点。停止条件:节点样本纯度过高或样本数过少时终止。二、数学公式与理论1.信息熵(InformationEntropy)衡量数据集的混乱程度:H(D)=−∑k=1Kpklog2pk
卡尔曼滤波算法从理论到实践:在STM32中的嵌入式实现
DOMINICHZL
STM32 算法 stm32 嵌入式硬件
摘要:卡尔曼滤波(KalmanFilter)是传感器数据融合领域的经典算法,在姿态解算、导航定位等嵌入式场景中广泛应用。本文将从公式推导、代码实现、参数调试三个维度深入解析卡尔曼滤波,并给出基于STM32硬件的完整工程案例。一、卡尔曼滤波核心思想1.1什么是卡尔曼滤波?卡尔曼滤波是一种最优递归估计算法,通过融合预测值(系统模型)与观测值(传感器数据),在噪声干扰环境下实现对系统状态的动态估计。其核
ffplay 使用文档介绍
码流怪侠
FFmpeg ffplay 播放器 音视频 直播 转码
ffplayffplay是一个简单的媒体播放器,它是FFmpeg项目的一部分。FFmpeg是一个广泛使用的多媒体框架,能够解码、编码、转码、复用、解复用、流化、过滤和播放几乎所有类型的媒体文件。ffplay主要用于测试和调试,因为它提供了一个命令行界面,可以方便地查看媒体文件的详细信息,如视频帧、音频波形等。它支持多种视频和音频格式,并且可以实时显示解码过程中的统计信息。使用文档原文地址:http
IEC104协议解析
上海研博数据
后端
一、IEC104协议核心特性与应用场景IEC104(IEC60870-5-104)是电力系统中广泛使用的通信协议,基于TCP/IP实现主从站(SCADA与RTU/变电站设备)的实时数据交互。其核心功能包括:1.四遥操作:遥测(YC):采集电压、电流等模拟量数据(如类型标识0x0D)。遥信(YX):监测开关状态等数字量信号(如M_SP_NA_1单点遥信)。遥控(YK):远程控制断路器
修改uview组件样式无效
走,带你去玩
uni-app
在自己的components组件目录下修改uview组件样式不起效果,添加如下代码与metnods平级即可exportdefault{options:{styleIsolation:'shared'},}
MySql索引使用
沐千熏
mysql 数据库
索引类型#主键索引:PRIMARY这设立主键后数据库自动建立索引,InnoDB为聚簇索引,主键索引列不能为空(NUll);#唯一索引:UNIQUE索引列的值必须唯一。可以为空值,但是必须只有一个;#普通索引(组合索引):NORMAL也称为非唯一索引,允许重复值和NULL值。一个索引可以包含多个列,多个列共同组成一个复杂的索引;#全文索引:FULLTEXTFullText(MySQL5.7之前,只有
android屏幕旋转生命周期,Activity、Fragment生命周期---横竖屏切换的生命周期
老K先生
android屏幕旋转生命周期
先贴出一张大家众所周知activity流程图onCreate():创建Activity调用,用于Activity的初始化,还有个Bundle类型的参数,可以访问以前存储的状态。onStart():Activity在屏幕上对用户可见时调用,但还不可与用户交互onRestart():在activity停止后,在再次启动之前被调用。onResume():Activity开始和用户交互的时候调用,这时该A
大数据面试之路 (一) 数据倾斜
愿与狸花过一生
大数据 面试 职场和发展
记录大数据面试历程数据倾斜大数据岗位,数据倾斜面试必问的一个问题。一、数据倾斜的表现与原因表现某个或某几个Task执行时间过长,其他Task快速完成。Spark/MapReduce作业卡在某个阶段(如reduce阶段),日志显示少数Task处理大量数据。资源利用率不均衡(如CPU、内存集中在某些节点)。常见场景Key分布不均:如某些Key对应的数据量极大(如用户ID为空的记录、热点事件)。数据分区
zookeeper程序员指南
weixin_30326741
java 运维 shell
1简介本文是为想要创建使用ZooKeeper协调服务优势的分布式应用的开发者准备的。本文包含理论信息和实践信息。本指南的前四节对各种ZooKeeper概念进行较高层次的讨论。这些概念对于理解ZooKeeper是如何工作的,以及如何使用ZooKeeper来进行工作都是必要的。这几节没有代码,但却要求读者对分布式计算相关的问题较为熟悉。本文的大多数信息以可独立访问的参考材料的形式存在。但是,在编写第一
ZooKeeper学习总结(1)——ZooKeeper入门介绍
一杯甜酒
ZooKeeper学习总结 Zookeeper
1.概述Zookeeper是Hadoop的一个子项目,它是分布式系统中的协调系统,可提供的服务主要有:配置服务、名字服务、分布式同步、组服务等。它有如下的一些特点:简单Zookeeper的核心是一个精简的文件系统,它支持一些简单的操作和一些抽象操作,例如,排序和通知。丰富Zookeeper的原语操作是很丰富的,可实现一些协调数据结构和协议。例如,分布式队列、分布式锁和一组同级别节点中的“领导者选举
一体化便携式气象站:从农业到环保,助力各行各业发展
tianhe8888_
气象站 便携式气象站 气象监测站
【TH-PQX5】随着科技的飞速进步,气象监测技术也在不断创新与发展。一体化便携式气象站,作为气象监测领域的佼佼者,以其小巧、便捷、功能全面的特点,正逐渐成为各行各业不可或缺的监测工具。从农业到环保,从科研到应急,一体化便携式气象站正以其独特的优势,助力各行各业的发展。一、一体化便携式气象站的基本概述一体化便携式气象站是一种集多种气象要素监测于一体的便携式设备。它通常包括温度传感器、湿度传感器、风
转基因大豆检测仪:快速精准识别,确保大豆安全品质
tianhe8888_
转基因检测仪 转基因检测设备
【TH-ZJY1】在现代农业与食品工业中,转基因作物的安全性一直是公众关注的焦点。为了确保大豆及其制品的安全品质,转基因大豆检测仪应运而生。这种高科技设备以其快速、精准的检测能力,为大豆产业链的安全监管提供了有力支持。一、工作原理基因检测技术转基因大豆检测仪主要依赖于先进的基因检测技术,如聚合酶链反应(PCR)、荧光原位杂交(FISH)或基因芯片等。这些技术能够特异性地识别大豆DNA中的转基因片段
雨滴谱仪:准确掌握降水情况,助力道路维护
tianhe8888_
雨滴谱仪 降水天气现象仪 雨滴
【TH-YD1】在气象监测与交通管理中,对道路降水情况的实时监测是至关重要的。雨滴谱仪作为一种高精度、智能化的降水天气现象监测设备,凭借其独特的工作原理和卓越的性能,在实时监测道路降水情况方面发挥着重要作用。一、引言降水是自然界中一种常见的天气现象,对道路交通、农业生产、城市排水等多个领域都有着重要影响。为了准确掌握降水情况,及时采取应对措施,科学家们研发了雨滴谱仪这一先进的气象监测设备。雨滴谱仪
函数的自定义以及调用函数相关
しんどぅ
学习 算法 c++
函数自定义以及调用函数相关1、函数的声明结构:【数据类型】【函数名】(参数列表);例如:intfrist(int,int);上面代码表示,定义了一个int类型的Frist函数,要接收两个int类型的数据。2、函数的定义intfrist(inta,intb){//定义intc=a+b;}如果函数有返回值,则需要用return返回;例如:intfrist(int,int);intfrist(inta,
云原生Serverless平台:无服务器计算的架构革命
桂月二二
云原生 serverless 架构
引言:从虚拟机到函数即服务(FaaS)AWSLambda每天处理数十万亿次请求,阿里巴巴函数计算支撑双十一亿级事件触发。KnativeServing实现秒级自动扩缩至零,Vercel边缘函数网络响应时间跌破50ms。CNCFOpenFaaS在GitHub斩获25k星,AzureFunctions支持毫秒级计费精度,GoogleCloudRun冷启动优化至200ms内。全球500强企业70%采用Se
【软件测试】功能自动化测试用例通常包含哪些要素
小马哥编程
自动化 测试用例
功能自动化测试用例是用于验证软件功能是否按预期工作的脚本或代码。与接口自动化测试用例不同,功能自动化测试用例通常关注用户界面(UI)和用户交互。以下是功能自动化测试用例的主要要素:1.用例ID唯一标识符,用于追踪和管理测试用例。2.用例名称简要描述测试的目标或功能。3.测试场景描述测试的具体场景或用户操作流程。例如:“验证用户登录功能”。4.前置条件执行测试前需要满足的条件。例如:用户已注册。浏览
RuoYi-Vue部署到Linux服务器(Jar+Nginx)
pingcode
若依框架 JAVA全栈开发笔记(全) JAVA运维笔记 ruoyi
一、本地环境准备源码下载、本地Jdk及Node.js环境安装,参考以下文章。附:RuoYi-Vue下载与运行二、服务器环境准备1.安装Jdk附:JDK8下载安装与配置环境变量(linux)2.安装MySQL附:MySQL8免安装版下载安装与配置(linux)3.安装Redis附:Redis下载安装与配置(linux)4.安装Nginx附:
【微信小程序】基本语法
小马哥编程
微信小程序 小程序
一、导入小程序选择代码目录项目配置文件appid当前小程序的AppIDprojectname当前小程序的项目名称变更AppID(视情况而定,如果没有开发权限时需要变更成个人的AppID)二、模板语法在页面中渲染数据时所用到的一系列语法叫做模板语法,对应到Vue中就是指令的概念。2.1数据绑定插值{{}}小程序中使用{{}}实现数据与模板的绑定,与Vue中不同的是无论是属性的绑定还是内容的绑定都必须
SpringBoot中的导入导出(SpringBoot导出word文档、Hutool导入excel、easypoi之easy导入数据库、导出excel文件、POI设置单元格式)
种豆走天下
spring boot java spring
SpringBoot中的导入导出java导出word文档1先准备好一个导出Word文档的模板。例如:2.打开doc文件后,文件中的另存为,然后选择保存类型为2003版本的(*.xml)3、刚生成的xml文件里面比较乱,要整理一下,方法如下:使用Eclipse/idea,新建一个jsp,把xml里面的东西覆盖更新刚才的jsp,ctrl+Shift+F/ctrl+alt+L把文件整理一下,在拷贝出来,
【UI自动化框架设计思路】runner:如何运行框架
小怪兽长大啦
UI自动化测试技术分享 ui 自动化 运维
一、简介**功能:**自动化测试的运行器,负责整合UI识别与UI操作、读取配置文件并执行测试用例步骤。参数:config_pth:配置文件的路径(字符串类型)。说明:Runner类是整个自动化测试流程的核心入口点,通过加载配置文件并结合UI操作类,执行测试用例的步骤。它将配置管理、UI操作和测试执行整合为一个完整的自动化测试流程。二、代码解析1.init方法**功能:**初始化Runner类,加载
Android Glide 的显示与回调模块原理源码级深度剖析
&有梦想的咸鱼&
Android Glide原理 Android开发大全 android glide
一、引言在当今的Android应用开发中,图片处理是一个至关重要的环节。从应用的图标展示到复杂的图片画廊,图片的加载和显示直接影响着用户体验。Glide作为一款功能强大且广泛使用的图片加载库,凭借其高效的性能、丰富的功能和简洁的API,成为了开发者的首选。其中,显示与回调模块更是Glide的核心部分,它负责将加载好的图片资源准确无误地显示在目标视图上,并在整个过程中提供各种回调机制,让开发者能够实
autoMate - AI实现电脑任务自动化的本地工具
小众AI
AI开源 人工智能 自动化 运维
GitHub:https://github.com/yuruotong1/autoMate更多AI开源软件:发现分享好用的AI工具、AI开源软件、AI模型、AI变现-小众AIautoMate是一款由开源开发的本地自动化工具,以AI+RPA(人工智能+机器人流程自动化)为核心特色。它将大型语言模型的智能理解与RPA的流程执行能力结合,用户只需用自然语言描述任务,如“整理桌面文件”或“生成周报”,即可
【POSIX 线程库函数】
niuTaylor
算法 linux 嵌入式 c语言 嵌入式软件
以下是关于POSIX线程库(pthread)的核心知识点总结,涵盖线程管理、同步机制及常见面试问题:一、线程基础1.线程创建与终止创建线程:pthread_createintpthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);thread:存储新线程的ID。a
从零打造工业级智能二维码识别系统:基于PyQt5与ZXingCpp的实战指南
蜡笔小新星
PyQt5 qt 开发语言 python 图像处理 经验分享 pyqt 扫码读码解码
文章目录第一章:系统全景解析1.1实时识别工作流图解1.2界面布局与功能分区说明1.3代码文件结构树形图第二章:环境搭建与依赖管理2.1必需组件清单2.2虚拟环境配置步骤2.3摄像头硬件检测方法第三章:多线程视频采集3.1VideoThread类设计剖析3.2图像采集核心循环3.3线程安全停止机制3.4信号槽通信实例第四章:图像预处理流水线4.1预处理方法开关实现4.2自适应二值化算法4.3图像格
深度学习:马氏距离
壹十壹
深度学习 深度学习 人工智能
马氏距离(MahalanobisDistance)是一种用于计算不同维度数据点之间距离的度量方法。它考虑了数据的协方差结构,因此在处理具有相关性的多维数据时更加有效。与欧氏距离不同,马氏距离不仅考虑了各个变量的量纲,还考虑了它们之间的相关性。公式马氏距离计算两个向量(x)和(y)之间的距离,定义为:DM(x,y)=(x−y)TS−1(x−y)\D_M(x,y)=\sqrt{(x-y)^TS^{-1
Velodyne16线激光雷达点云数据中的线束(ring)是如何分布的
壹十壹
激光雷达 编辑器
将sensor_msgs::PointCloud2转为pcl::PointCloud后的点云数据线束(ring)是从下往上进行递增排序。在下图中线束0为深蓝色,线束1是红色,线束2为淡蓝色,线束3为橘黄色,线束4为绿色,线束6为黄色。(一帧激光雷达点云的强度值在RVIZ中显示的颜色与该帧点云数据中激光雷达强度值的最大值有关)
TOMCAT在POST方法提交参数丢失问题
357029540
java tomcat jsp
摘自http://my.oschina.net/luckyi/blog/213209
昨天在解决一个BUG时发现一个奇怪的问题,一个AJAX提交数据在之前都是木有问题的,突然提交出错影响其他处理流程。
检查时发现页面处理数据较多,起初以为是提交顺序不正确修改后发现不是由此问题引起。于是删除掉一部分数据进行提交,较少数据能够提交成功。
恢复较多数据后跟踪提交FORM DATA ,发现数
在MyEclipse中增加JSP模板 删除-2008-08-18
ljy325
jsp xml MyEclipse
在D:\Program Files\MyEclipse 6.0\myeclipse\eclipse\plugins\com.genuitec.eclipse.wizards_6.0.1.zmyeclipse601200710\templates\jsp 目录下找到Jsp.vtl,复制一份,重命名为jsp2.vtl,然后把里面的内容修改为自己想要的格式,保存。
然后在 D:\Progr
JavaScript常用验证脚本总结
eksliang
JavaScript javaScript表单验证
转载请出自出处:http://eksliang.iteye.com/blog/2098985
下面这些验证脚本,是我在这几年开发中的总结,今天把他放出来,也算是一种分享吧,现在在我的项目中也在用!包括日期验证、比较,非空验证、身份证验证、数值验证、Email验证、电话验证等等...!
&nb
微软BI(4)
18289753290
微软BI SSIS
1)
Q:查看ssis里面某个控件输出的结果:
A MessageBox.Show(Dts.Variables["v_lastTimestamp"].Value.ToString());
这是我们在包里面定义的变量
2):在关联目的端表的时候如果是一对多的关系,一定要选择唯一的那个键作为关联字段。
3)
Q:ssis里面如果将多个数据源的数据插入目的端一
定时对大数据量的表进行分表对数据备份
酷的飞上天空
大数据量
工作中遇到数据库中一个表的数据量比较大,属于日志表。正常情况下是不会有查询操作的,但如果不进行分表数据太多,执行一条简单sql语句要等好几分钟。。
分表工具:linux的shell + mysql自身提供的管理命令
原理:使用一个和原表数据结构一样的表,替换原表。
linux shell内容如下:
=======================开始
本质的描述与因材施教
永夜-极光
感想 随笔
不管碰到什么事,我都下意识的想去探索本质,找寻一个最形象的描述方式。
我坚信,世界上对一件事物的描述和解释,肯定有一种最形象,最贴近本质,最容易让人理解
&
很迷茫。。。
随便小屋
随笔
小弟我今年研一,也是从事的咱们现在最流行的专业(计算机)。本科三流学校,为了能有个更好的跳板,进入了考研大军,非常有幸能进入研究生的行业(具体学校就不说了,怕把学校的名誉给损了)。
先说一下自身的条件,本科专业软件工程。主要学习就是软件开发,几乎和计算机没有什么区别。因为学校本身三流,也就是让老师带着学生学点东西,然后让学生毕业就行了。对专业性的东西了解的非常浅。就那学的语言来说
23种设计模式的意图和适用范围
aijuans
设计模式
Factory Method 意图 定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method 使一个类的实例化延迟到其子类。 适用性 当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由它的子类来指定它所创建的对象的时候。 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。
Abstr
Java中的synchronized和volatile
aoyouzi
java volatile synchronized
说到Java的线程同步问题肯定要说到两个关键字synchronized和volatile。说到这两个关键字,又要说道JVM的内存模型。JVM里内存分为main memory和working memory。 Main memory是所有线程共享的,working memory则是线程的工作内存,它保存有部分main memory变量的拷贝,对这些变量的更新直接发生在working memo
js数组的操作和this关键字
百合不是茶
js 数组操作 this关键字
js数组的操作;
一:数组的创建:
1、数组的创建
var array = new Array(); //创建一个数组
var array = new Array([size]); //创建一个数组并指定长度,注意不是上限,是长度
var arrayObj = new Array([element0[, element1[, ...[, elementN]]]
别人的阿里面试感悟
bijian1013
面试分享 工作感悟 阿里面试
原文如下:http://greemranqq.iteye.com/blog/2007170
一直做企业系统,虽然也自己一直学习技术,但是感觉还是有所欠缺,准备花几个月的时间,把互联网的东西,以及一些基础更加的深入透析,结果这次比较意外,有点突然,下面分享一下感受吧!
&nb
淘宝的测试框架Itest
Bill_chen
spring maven 框架 单元测试 JUnit
Itest测试框架是TaoBao测试部门开发的一套单元测试框架,以Junit4为核心,
集合DbUnit、Unitils等主流测试框架,应该算是比较好用的了。
近期项目中用了下,有关itest的具体使用如下:
1.在Maven中引入itest框架:
<dependency>
<groupId>com.taobao.test</groupId&g
【Java多线程二】多路条件解决生产者消费者问题
bit1129
java多线程
package com.tom;
import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.loc
汉字转拼音pinyin4j
白糖_
pinyin4j
以前在项目中遇到汉字转拼音的情况,于是在网上找到了pinyin4j这个工具包,非常有用,别的不说了,直接下代码:
import java.util.HashSet;
import java.util.Set;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin
org.hibernate.TransactionException: JDBC begin failed解决方案
bozch
ssh 数据库异常 DBCP
org.hibernate.TransactionException: JDBC begin failed: at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:68) at org.hibernate.impl.SessionImp
java-并查集(Disjoint-set)-将多个集合合并成没有交集的集合
bylijinnan
java
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.ut
Java PrintWriter打印乱码
chenbowen00
java
一个小程序读写文件,发现PrintWriter输出后文件存在乱码,解决办法主要统一输入输出流编码格式。
读文件:
BufferedReader
从字符输入流中读取文本,缓冲各个字符,从而提供字符、数组和行的高效读取。
可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。
通常,Reader 所作的每个读取请求都会导致对基础字符或字节流进行相应的读取请求。因
[天气与气候]极端气候环境
comsci
环境
如果空间环境出现异变...外星文明并未出现,而只是用某种气象武器对地球的气候系统进行攻击,并挑唆地球国家间的战争,经过一段时间的准备...最大限度的削弱地球文明的整体力量,然后再进行入侵......
那么地球上的国家应该做什么样的防备工作呢?
&n
oracle order by与union一起使用的用法
daizj
UNION oracle order by
当使用union操作时,排序语句必须放在最后面才正确,如下:
只能在union的最后一个子查询中使用order by,而这个order by是针对整个unioning后的结果集的。So:
如果unoin的几个子查询列名不同,如
Sql代码
select supplier_id, supplier_name
from suppliers
UNI
zeus持久层读写分离单元测试
deng520159
单元测试
本文是zeus读写分离单元测试,距离分库分表,只有一步了.上代码:
1.ZeusMasterSlaveTest.java
package com.dengliang.zeus.webdemo.test;
import java.util.ArrayList;
import java.util.List;
import org.junit.Assert;
import org.j
Yii 截取字符串(UTF-8) 使用组件
dcj3sjt126com
yii
1.将Helper.php放进protected\components文件夹下。
2.调用方法:
Helper::truncate_utf8_string($content,20,false); //不显示省略号 Helper::truncate_utf8_string($content,20); //显示省略号
&n
安装memcache及php扩展
dcj3sjt126com
PHP
安装memcache tar zxvf memcache-2.2.5.tgz cd memcache-2.2.5/ /usr/local/php/bin/phpize (?) ./configure --with-php-confi
JsonObject 处理日期
feifeilinlin521
java json JsonOjbect JsonArray JSONException
写这边文章的初衷就是遇到了json在转换日期格式出现了异常 net.sf.json.JSONException: java.lang.reflect.InvocationTargetException 原因是当你用Map接收数据库返回了java.sql.Date 日期的数据进行json转换出的问题话不多说 直接上代码
&n
Ehcache(06)——监听器
234390216
监听器 listener ehcache
监听器
Ehcache中监听器有两种,监听CacheManager的CacheManagerEventListener和监听Cache的CacheEventListener。在Ehcache中,Listener是通过对应的监听器工厂来生产和发生作用的。下面我们将来介绍一下这两种类型的监听器。
activiti 自带设计器中chrome 34版本不能打开bug的解决
jackyrong
Activiti
在acitivti modeler中,如果是chrome 34,则不能打开该设计器,其他浏览器可以,
经证实为bug,参考
http://forums.activiti.org/content/activiti-modeler-doesnt-work-chrome-v34
修改为,找到
oryx.debug.js
在最头部增加
if (!Document.
微信收货地址共享接口-终极解决
laotu5i0
微信开发
最近要接入微信的收货地址共享接口,总是不成功,折腾了好几天,实在没办法网上搜到的帖子也是骂声一片。我把我碰到并解决问题的过程分享出来,希望能给微信的接口文档起到一个辅助作用,让后面进来的开发者能快速的接入,而不需要像我们一样苦逼的浪费好几天,甚至一周的青春。各种羞辱、谩骂的话就不说了,本人还算文明。
如果你能搜到本贴,说明你已经碰到了各种 ed
关于人才
netkiller.github.com
工作 面试 招聘 netkiller 人才
关于人才
每个月我都会接到许多猎头的电话,有些猎头比较专业,但绝大多数在我看来与猎头二字还是有很大差距的。 与猎头接触多了,自然也了解了他们的工作,包括操作手法,总体上国内的猎头行业还处在初级阶段。
总结就是“盲目推荐,以量取胜”。
目前现状
许多从事人力资源工作的人,根本不懂得怎么找人才。处在人才找不到企业,企业找不到人才的尴尬处境。
企业招聘,通常是需要用人的部门提出招聘条件,由人
搭建 CentOS 6 服务器 - 目录
rensanning
centos
(1) 安装CentOS
ISO(desktop/minimal)、Cloud(AWS/阿里云)、Virtualization(VMWare、VirtualBox)
详细内容
(2) Linux常用命令
cd、ls、rm、chmod......
详细内容
(3) 初始环境设置
用户管理、网络设置、安全设置......
详细内容
(4) 常驻服务Daemon
【求助】mongoDB无法更新主键
toknowme
mongodb
Query query = new Query(); query.addCriteria(new Criteria("_id").is(o.getId())); &n
jquery 页面滚动到底部自动加载插件集合
xp9802
jquery
很多社交网站都使用无限滚动的翻页技术来提高用户体验,当你页面滑到列表底部时候无需点击就自动加载更多的内容。下面为你推荐 10 个 jQuery 的无限滚动的插件:
1. jQuery ScrollPagination
jQuery ScrollPagination plugin 是一个 jQuery 实现的支持无限滚动加载数据的插件。
2. jQuery Screw
S