您的位置:首页 > 编程语言 > Java开发

Java编程热门问题总结——基础语法篇

2017-06-01 11:17 330 查看
  经过多种渠道的搜集,对Java程序员在编程过程中常见的问题及解答作一个整理。

1、Java += 操作符实质

  我之前以为: i += j 等同于 i = i + j; 但假设有:

int i = 5;
long j = 8;
1
2




1
2
  这时 i = i + j 不能编译,但 i += j 却可以编译。这说明两者还是有差别的,这是否意味着i += j实际上等同于 i= (type of i) (i + j)呢?

  其实这个问题在官方文档中已经解答了。对复合赋值表达式来说,E1 op= E2 (诸如 i += j; i -= j 等等),其实是等同于 E1 = (T)((E1) op (E2)),其中,T是E1这个元素的类型。举例来说,如下的代码:

short x = 3;
x += 4.6;
1
2




1
2
  等同于:

short x = 3;
x = (short)(x + 4.6);
1
2




1
2

2、将数组转换为List

   假设有数组:

Element[] array = {new Element(1),new Element(2),new Element(3)};
1




1
  如何将其转换为ArrayList<Element> arraylist = ???

  回答1:

ArrayList<Element> arraylist = new ArrayList<Element>(Arrays.asList(array));
1




1
  回答2:

List<Element> list = Arrays.asList(array);
//或者
List<Element> list = Arrays.asList(new Element(1),new Element(2),new Element(3));
1
2
3




1
2
3
  回答2方法返回的是基于数组的List视图(List view)。所以,这种方式是将数组转换为List的最快的方式。但是,Arrays.asList()方法返回的列表是Arrays.ArrayList类型的,并不是java.util.ArrayList,这个类型是Arrays的一个私有内部类,这个内部类并没有直接实现java.util.List接口,而是继承自AbstractCollection这个类,这个java.util.Arrays.ArrayList类有set(),get(),contains()方法,但是没有任何add()
方法,所以它是固定大小的,这个类是不允许向列表中添加数据的,这个可以自己去看下AbstractCollection这个类的源码。

  像回答2这样做生成的list,是定长的。也就是说,如果你对它做add或者remove,都会抛UnsupportedOperationException。虽然不能进行删除、添加操作,但可以使用set()方法进行修改元素操作,因为回答2返回的是基于原数组的List视图,所以,当我们使用set方法修改了List中的元素的时候,那么原来的数组也会跟着改变(这是视图的特性)。

  而采用下面这种类似于回答1给出的操作方式就和前面完全不同了,你操作的是java.util.ArrayList对象,它是直接实现List接口的,因此可以正常添加数据到集合中

List<Element> list = new ArrayList<Element>(Arrays.asList(array));
1




1
  如果希望避免采用回答2方式中引入的两个坑,除了用回答1的方式外,还可以用下面这种方式:

List<Element> list = new ArrayList<Element>();
Collections.addAll(list, array);
1
2




1
2
  该方法实际上是将数组的内容复制到ArrayList中,因为是复制内容到ArrayList中,所以我们对ArrayList进行修改、添加、删除操作都不会影响原来的数组。

3、如何遍历Map对象

   在Java中有多种遍历HashMAp的方法。在此回顾一下最常见的方法和它们各自的优缺点。由于所有的Map都实现了Map接口,所以接下来方法适用于所有Map(如:HaspMap,TreeMap,LinkedMap,HashTable等等)。

方法1 使用For-Each迭代entries

   这是最常见的方法,并在大多数情况下j是更可取的。当你在循环中需要使用Map的键和值时,就可以使用这个方法:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for(Map.Entry<Integer, Integer> entry : map.entrySet()) {
System.out.println("key = " + entry.getKey() + ", value = " +
entry.getValue())
}
1
2
3
4
5




1
2
3
4
5
   注意:For-Each循环是Java5新引入的,所以只能在Java5以上的版本中使用。如果你遍历的map是null的话,For-Each循环会抛出NullPointerException异常,所以在遍历之前你应该先判断map是否为空引用。这种方法只能遍历,不能在遍历过程中删除元素。

方法2 使用For-Each迭代keys和values

   如果你只需要用到map的keys或values中的一个时,你可以遍历KeySet或者values而不是entrySet:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();

//iterating over keys only
for (Integer key : map.keySet()) {
System.out.println("Key = " + key);
}

//iterating over values only
for (Integer value : map.values()) {
System.out.println("Value = " + value);
}
1
2
3
4
5
6
7
8
9
10
11




1
2
3
4
5
6
7
8
9
10
11
   这个方法比entrySet迭代具有轻微的性能优势(大约快10%)并且代码更简洁。

方法3 使用Iterator迭代

   使用泛型的代码:

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<Integer, Integer> entry = entries.next();
System.out.println("Key = " + entry.getKey() + ", Value = " +
entry.getValue());
}
1
2
3
4
5
6
7




1
2
3
4
5
6
7
   不使用泛型的代码:

Map map = new HashMap();
Iterator entries = map.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry entry = (Map.Entry) entries.next();
Integer key = (Integer)entry.getKey();
Integer value = (Integer)entry.getValue();
System.out.println("Key = " + key + ", Value = " + value);
}
1
2
3
4
5
6
7
8




1
2
3
4
5
6
7
8
   可以使用同样的技术迭代keyset或者values。这个似乎有点多余但它具有自己的优势。首先,它是遍历老的java版本map的唯一方法。另外一个重要的特性是可以让你在迭代的时候从map中删除entries的(通过调用iterator.remover())唯一方法,如果你试图在For-Each迭代的时候删除entries,你将会得到unpredictable resultes 异常。从性能方法看,这个方法等价于使用For-Each迭代。

方法4 迭代keys并搜索values(低效的)

Map<Integer, Integer> map = new HashMap<Integer, Integer>();
for (Integer key : map.keySet()) {
Integer value = map.get(key);
System.out.println("Key = " + key + ", Value = " + value);
}
1
2
3
4
5




1
2
3
4
5
   这个方法看上去比方法1更简洁,但是实际上它更慢更低效,通过key得到value值更耗时(这个方法在所有实现map接口的map中比方法1慢20%-200%)。如果你安装了FindBugs,它将检测并警告你这是一个低效的迭代。这个方法应该避免。

   总结:如果你只需要使用key或者value使用方法2,如果你坚持使用java的老版本(Java5 以前的版本)或者打算在迭代的时候移除entries,使用方法3。其他情况请使用方法1。避免使用方法4。

4、如何测试一个数组是否包含指定的值

   指定数组,如:

public static final String[] VALUES = new String[] {"AB","BC","CD","AE"};
1




1
   现在指定一个值s,有哪些比较好的方式,判断这个数组 VALUES 是否包含值 s?

简单且优雅的方法

  1、使用Arrays.asList(…).contains(…)方法;

  2、使用Apache Commons Lang3包中的ArrayUtils.contains()方法

String[] fieldsToInclude = { "id", "name", "location" };
if (ArrayUtils.contains(fieldsToInclude, "id")) {
// Do some stuff.
}
1
2
3
4




1
2
3
4

  引申:Apache Commons是一个非常有用的工具包,能够解决各种能用问题,常用的工具类有ArrayUtils、DateUtils、DateFormatUtils、NumberUtils、CollectionUtils等。

自己写逻辑

   问题的本质,其实是一个查找的问题,即查找一个数组是否包含某个值。对于原始类型,若是无序的数组,可以直接写一个 for 循环:

public static boolean useLoop(String[] arr, String targetValue) {
for(String s: arr) {
if(s.equals(targetValue))
return true;
}
return false;
}
1
2
3
4
5
6
7




1
2
3
4
5
6
7
   若是有序的数组,可以考虑二分查找或者其他查找算法

public static boolean useArraysBinarySearch(String[] arr, String targetValue) {
int a =  Arrays.binarySearch(arr, targetValue);
if(a >= 0)
return true;
else
return false;
}
1
2
3
4
5
6
7




1
2
3
4
5
6
7

5、如何将String转换为Int

   有两种方式

Integer x = Integer.valueOf(str);
// or
int y = Integer.parseInt(str);
1
2
3




1
2
3
   这两种方式有一点点不同:valueOf返回的是java.lang.Integer的实例;parseInt返回的是基本数据类型int。Short.valueOf/parseShort,Long.valueOf/parseLong等也是有类似差别。

   另外还需注意的是,在做int类型转换时,可能会抛出NumberFormatException,因此要做好异常捕获。

int foo;
String StringThatCouldBeANumberOrNot = "26263Hello";
//will throw exception
String StringThatCouldBeANumberOrNot2 = "26263";
//will not throw exception
try {
foo = Integer.parseInt(StringThatCouldBeANumberOrNot);
} catch (NumberFormatException e) {
//Will Throw exception!
//do something! anything to handle the exception.
}

try {
foo = Integer.parseInt(StringThatCouldBeANumberOrNot2);
} catch (NumberFormatException e) {
//No problem this time but still it's necessary to care about exceptions.
//Never trust user input :)
//do something! anything to handle the exception.
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

6、如何便捷地将两个数组合到一起

   一行代码搞定,Apache Commons Lang library 中的ArrayUtils.addAll(T[], T…)方法就是专门干这事的:

String[] both = ArrayUtils.addAll(first, second);
1




1
   不借助依赖包的非泛型写法,把下面的Foo替换成你自己的类名:

public Foo[] concat(Foo[] a, Foo[] b) {
int aLen = a.length;
int bLen = b.length;
Foo[] c= new Foo[aLen+bLen];
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
1
2
3
4
5
6
7
8




1
2
3
4
5
6
7
8
   不借助依赖包的泛型写法:

public <T> T[] concatenate (T[] a, T[] b) {
int aLen = a.length;
int bLen = b.length;
@SuppressWarnings("unchecked")
T[] c = (T[]) Array.newInstance(a.getClass().getComponentType(), aLen+bLen);
System.arraycopy(a, 0, c, 0, aLen);
System.arraycopy(b, 0, c, aLen, bLen);
return c;
}
1
2
3
4
5
6
7
8
9




1
2
3
4
5
6
7
8
9
   注意:泛型的方案不适用于基本数据类型(int,boolean……)。

7、Map<Key,Value>基于Value值排序

方法1 使用TreeMap

   可以参考下面的代码:

public class Testing {
public static void main(String[] args) {
HashMap<String,Double> map = new HashMap<String,Double>();
ValueComparator bvc =  new ValueComparator(map);
TreeMap<String,Double> sorted_map = new TreeMap<String,Double>(bvc);

map.put("A",99.5);
map.put("B",67.4);
map.put("C",67.4);
map.put("D",67.3);

System.out.println("unsorted map: "+ map);
sorted_map.putAll(map);
System.out.println("results: "+ sorted_map);
}
}

class ValueComparator implements Comparator<String> {
Map<String, Double> base;
public ValueComparator(Map<String, Double> base) {
this.base = base;
}
// Note: this comparator imposes orderings that are inconsistent with equals.
public int compare(String a, String b) {
if (base.get(a) >= base.get(b)) {
return -1;
} else {
return 1;
} // returning 0 would merge keys
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
   注意:如果不自己实现一个定制的Comparator,Treemap默认是用key来排序。

方法2 先通过linkedList排好序,再放到LinkedHashMap中

public class MapUtil {
public static <K, V extends Comparable<? super V>> Map<K, V>
sortByValue(Map<K, V> map) {
List<Map.Entry<K, V>> list = new LinkedList<Map.Entry<K, V>>( map.entrySet() );
Collections.sort( list, new Comparator<Map.Entry<K, V>>() {
public int compare( Map.Entry<K, V> o1, Map.Entry<K, V> o2) {
return (o1.getValue()).compareTo( o2.getValue());
}
});

Map<K, V> result = new LinkedHashMap<K, V>();
for (Map.Entry<K, V> entry : list) {
result.put( entry.getKey(), entry.getValue());
}
return result;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
   注意:这两种方法,我简单测试了下,如果map的size在十万级别以上,两者的耗时都是几百毫秒,第二个方法会快一些。否则,第一个方法快一些。因此,如果你处理的map,都是几十万级别以下的大小,两种方法可随意使用。

8、JavaBean 到底是什么

   JavaBean 只是一个标准:

   1、所有的属性是私有的(通过getters/setters处理属性)

   2、一个公有的无参数的构造器

   3、实现了序列化(Serializable)

   就这些,它只是一个规范。但是很多的类库都是依赖于这些预定。

   对于Serializable,看一下API文档的解释:

   实现java.io.Serializable接口的类能串行化。不实现此接口的类不会有任何状态的序列化和反序列化。可序列化类的所有子类型本身都是可序列化。序列化接口没有方法或字段,仅用于标识的可序列化的语义。

   换句话说,序列化的对象可以被写入流,文件,对象数据库等。另外,一个JavaBean类和一个普通的类没有语法区别,如果遵循上面的标准的话,一个普通的类可以认为是一个JavaBean类。

   之所以需要JavaBean,是因为这样预定义了一种类的格式,一些库能依据这个约定的格式,来做一些自动化处理。

9、fnally块总会被执行吗

   有一个 try/catch 代码块,其中包含一个打印语句。finally代码块总会被执行么?

try {
something();
return success;
}
catch (Exception e) {
return failure;
}
finally {
System.out.println("i don't know if this will get printed out.");
}
1
2
3
4
5
6
7
8
9
10




1
2
3
4
5
6
7
8
9
10
   答案是finally块会被调用。只有出现以下情况, finally块才不会被调用:

   1、当你使用 System.exit() 后

   2、其他线程干扰了现在正在运行的线程(通过 interrupt 方法)

   3、JVM 崩溃( crash )了

   示例代码:

public class Test {
public static void main(String args[]) {
System.out.println(Test.test());
}

public static int test() {
try {
return 0;
}
finally {
System.out.println("finally trumps return.");
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14




1
2
3
4
5
6
7
8
9
10
11
12
13
14
   运行结果:

finally trumps return.
0
1
2




1
2

10、HashMap和Hashtable的区别

   在Java中HashMap和Hashtable的区别? 哪一个对于多线程应用程序更好?

   1、Hashtable是同步的,加了synchronized锁,而HashMap不是。没有加synchronized锁的对象,性能通常比加了synchronized锁的对象要更好一些,因此,如果是非多线程程序,不需要考虑锁、同步等问题,那么使用HashMap更好。

   2、Hashtable不允许有空的键或值。HashMap允许空键和空值。

   3、 HashMap有一个子类LinkedHashMap,对这个类对象进行迭代时,它的顺序是有序的(按插入顺序排序)。如有需要,你也能轻易的从LinkedHashMap转化成HashMap。Hashtable就没那么简单了,

   总之,如果你无需关心同步(synchronized)问题,建议用HashMap;反之,可以考虑使用ConcurrentHashMap。

11、HashMap和ConcurrentHashMap的区别

   1、HashMap不是线程安全的。ConcurrentHashMap是线程安全的。

   2、 ConcurrentHashMap将整个Hash桶进行了分段segment,也就是将这个大的数组分成了几个上的片段,每个小的片段segment上面都有锁存在,那么在插入元素的时候,就需要先找到应该插入到哪一个片段segment,然后再在这个片段上面插入,而且还需要获取segment锁。

   3、 ConcurrentHashMap让锁的粒度更精细一些,并发性能更好。

   在Java中有多种遍历HashMap的方法。在此回顾一下最常见的方法和它们各自的优缺点。由于所有的Map都实现了Map接口,所以接下来方法适用于所有Map(如:HaspMap,TreeMap,LinkedMap,HashTable等等)。

12、Arrays.asList()的返回对象不是java.util.ArrayList类型

   使用工具类Arrays.asList()把数组转换成集合时,不能使用其修改集合相关的方法,它的add/remove/clear方法会抛出UnsupportedOperationException异常。asList的返回对象是一个Arrays的内部类,并没有实现集合的修改方法。Arrays.asList体现的是适配器模式,只是转换接口,后台的数据仍是数组。

String[] str = new String[]{"a","b"};
List list = Arrays.asList(str);


   第一种情况:list.add("c");运行时异常。

   第二种情况:str[0]="gujin";那么list.get(0)也会随之修改。 

   同asList方法同时,subList 返回的也是ArrayList的内部类SubList,并不是java.util.ArrayList ,它是ArrayList 的一个视图,对于subList子列表的所有操作最终会反映到原列表上。数组转换成List的合理方法见本文条目二。   

13、比较java枚举成员使用equal还是==

   Java枚举会被编译成一个包含私有构造参数和一堆静态方法的类,当比较两个枚举的时候,使用equals()方法与使用==有区别吗,应该用哪种方法?

  答案是两种方法都行,如果你看过枚举的源码,你会发现在源码中,equals也等同于非常简单的== 。 我使用 == ,因为无论如何,这个左值是可以为 null的

   这里补充 java.lang.Enum 中equals()方法的源代码:

public final boolean equals(Object other) {
return this == other;
}
1
2
3




1
2
3
   具体来说,那些提供恰当实例控制的不可变类能够保证==是可用的,枚举刚好符合这个条件。考虑静态工厂方法代替构造器,它使得不可变类可以确保不会存在两个相等的实例(这是用静态工厂方法代替构造器的一个优势,详情可见《Effective Java》中的相关条款),即当且仅当a==b的时候才有a.equals(b)为true。如果类保证了这一点,它的客户端就可以使用“==”操作符来代替equals(Object)方法,这样可以提升性能。枚举类型保证了这一点。

  通常来说 == 不是equals()的一个备选方案,无论如何有2个重要的不同处需要考虑:

   1、== 不会抛出 NullPointerException

enum Color { BLACK, WHITE };

Color nothing = null;
if (nothing == Color.BLACK);      // runs fine
if (nothing.equals(Color.BLACK)); // throws NullPointerException
1
2
3
4
5




1
2
3
4
5
   2、== 在编译期检测类型兼容性

enum Color { BLACK, WHITE };
enum Chiral { LEFT, RIGHT };

if (Color.BLACK.equals(Chiral.LEFT)); // compiles fine
if (Color.BLACK == Chiral.LEFT);      // DOESN'T COMPILE!!! Incompatible types!
1
2
3
4
5




1
2
3
4
5
   总而言之,两种比较方法都行,使用 == 更好, 因为:

   1、更快

   2、运行时是安全的

   3、编译期也是安全的

14、serialVersionUID 有什么作用

   当一个对象实现 Serializable 接口时,多数IDE会提示声明一个静态常量 serialVersionUID(版本标识),那 serialVersionUID到底有什么作用呢?应该如何使用 serialVersionUID?

   serialVersionUID是实现Serializable接口而来的,而Serializable 则是应用于Java对象序列化/反序列化。对象的序列化主要有两种用途:

   1、把对象序列化成字节码,保存到指定介质上(如磁盘等)

   2、用于网络传输

   现在反过来说就是,serialVersionUID会影响到上述所提到的两种行为。那到底会造成什么影响呢?

   serialVersionUID是Java为每个序列化类产生的版本标识,可用来保证在反序列时,发送方发送的和接受方接收的是可兼容的对象。如果接收方接收的类的 serialVersionUID与发送方发送的 serialVersionUID不一致,进行反序列时会抛出 InvalidClassException。序列化的类可显式声明 serialVersionUID 的值,如下:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 1L;
1




1
   当显式定义serialVersionUID的值时,Java 根据类的多个方面(具体可参考Java 序列化规范)动态生成一个默认的 serialVersionUID 。尽管这样,还是建议你在每一个序列化的类中显式指定 serialVersionUID 的值,因为不同的 jdk 编译很可能会生成不同的 serialVersionUID 默认值,进而导致在反序列化时抛出 InvalidClassExceptions 异常。所以,为了保证在不同的
jdk 编译实现中,其 serialVersionUID 的值也一致,可序列化的类必须显式指定 serialVersionUID 的值。另外,serialVersionUID 的修饰符最好是 private,因为 serialVersionUID不能被继承,所以建议使用 private 修饰 serialVersionUID。

   举例说明如下,现在尝试通过将一个类 Person 序列化到磁盘和反序列化来说明 serialVersionUID 的作用。

public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
private String address;

public Person() {
}

public Person(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
   简单测试一下:

@Test
public void testversion1L() throws Exception {
File file = new File("person.out");
// 序列化
ObjectOutputStream oout = new ObjectOutputStream(new FileOutputStream(file));
Person person = new Person("John", 21, "广州");
oout.writeObject(person);
oout.close();
// 反序列化
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Object newPerson = oin.readObject();
oin.close();
System.out.println(newPerson);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14




1
2
3
4
5
6
7
8
9
10
11
12
13
14
   测试结果:

Person{name='John', age=21, address='广州'}
1




1
   测试发现没有什么问题。有一天,因发展需要, 需要在Person中增加了一个字段email,如下:

public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private Integer age;
private String address;

private String email;

public Person() {
}

public Person(String name, Integer age, String address) {
this.name = name;
this.age = age;
this.address = address;
}

public Person(String name, Integer age, String address,String email) {
this.name = name;
this.age = age;
this.address = address;
this.email = email;
}

@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address='" + address + '\'' +
", email='" + email + '\'' +
'}';
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
   这时我们假设和之前序列化到磁盘的 Person 类是兼容的,便不修改版本标识 serialVersionUID。再次测试如下:

@Test
public void testversion1LWithExtraEmail() throws Exception {
//反序列化
File file = new File("person.out");
ObjectInputStream oin = new ObjectInputStream(new FileInputStream(file));
Object newPerson = oin.readObject();
oin.close();
System.out.println(newPerson);
}
1
2
3
4
5
6
7
8
9




1
2
3
4
5
6
7
8
9
   测试结果:

Person{name='John', age=21, address='广州', email='null'}
1




1
   将以前序列化到磁盘的旧 Person 反序列化到新 Person 类时,没有任何问题。可当我们增加 email 字段后,不作向后兼容。即放弃原来序列化到磁盘的 Person 类,这时我们可以将版本标识提高,如下:

private static final long serialVersionUID = 2L;
1




1
   再次进行反序列化,则会报错,如下:

java.io.InvalidClassException: other7.Person; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2
1




1



   谈到这里,我们大概可以清楚,serialVersionUID就是控制版本是否兼容的,若我们认为修改的 Person 是向后兼容的,则不修改 serialVersionUID;反之,则提高serialVersionUID的值。再回到一开始的问题,为什么IDE会提示声明 serialVersionUID 的值呢?

   因为若不显式定义 serialVersionUID 的值,Java 会根据类细节自动生成 serialVersionUID 的值,如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,也有可能会导致不同的serialVersionUID。所以
IDE才会提示声明 serialVersionUID 的值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java 编程