Java 同时返回多个不同类型
前言
虽然对于这种需求不常用,且比较冷门,但是还是有其存在的价值,再次做一下整理。我们常用的return语句只允许返回单个对象,相对的解决办法就是创建一个对象,用它来持有想要返回的多个对象。
实现这种功能,还要归功于Java1.5的新特性-泛型,我们利用泛型,可以一次性地解决该问题,以后再也不用在这个问题上浪费时间了,并且,我们可以再编译期就能够确保类型安全。
你也许已经想到使用集合可以实现我们的需求,但是虽然一次可以返回多个值,但是其类型都是相同的,并不完全符合我们的需求。
我们需要引入一个概念:元组(tuple),元组也称为数据传送对象或信使。元组是将一组对象直接打包存储于其中的一个单一对象,这个容器对象允许读取其中元素,但是不允许向其中存放新的对象。
通常,元组可以具有任意长度,同时元组中的对象可以是任意不同的类型。我们能够为每一个对象指明其类型,并且可以正确读取到数据,这就是元组可以提供的功能。我们要处理不同长度的问题,需要创建多个不同的元组。
首先我们创建一个2维元组
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//: net/mindview/util/TwoTuple.java(Java编程思想_代码_目录)
package net.mindview.util;
public class TwoTuple<A, B> {
public final A first;
public final B second;
public TwoTuple(A a, B b) {
first = a;
second = b;
}
public String toString() {
return "(" + first + ", " + second + ")" ;
}
}
|
构造器捕获了要存储的对象,而toString()方法是一个便利函数,用来显示列表中的值。
注意:元组隐含地保持了其中元素的次序。
阅读上面的代码,以及根据元组的定义,你一定会感到诧异,设计思路不是应该将first和second声明为private,然后生成这两个变量的get方法吗?
以上是我们大多数人的思维,但是我们仔细分析上面的代码,可以发现完全符合我们的要求。首先我们可以读取first和second,并且因为使用了final声明,我们就无法在修改其值。我们对比这两种写法,很显然,上面给出的代码更加合理,更加简洁明了。
还有另一种设计考虑,即你确实希望允许客户端程序员改变first或second所引用的对象。然而,采用上面的形式无疑是更安全的做法,这样的话,如果程序员想要使用具有不同元素的元组,就强制要求他们另外创建一个新的TwoTuple对象。
我们可以利用继承机制实现长度更长的元组
1
2
3
4
5
6
7
8
9
10
11
12
13
|
//: net/mindview/util/ThreeTuple.java
package net.mindview.util;
public class ThreeTuple<A,B,C> extends TwoTuple<A,B> {
public final C third;
public ThreeTuple(A a, B b, C c) {
super (a, b);
third = c;
}
public String toString() {
return "(" + first + ", " + second + ", " + third + ")" ;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
//: net/mindview/util/FourTuple.java
package net.mindview.util;
public class FourTuple<A,B,C,D> extends ThreeTuple<A,B,C> {
public final D fourth;
public FourTuple(A a, B b, C c, D d) {
super (a, b, c);
fourth = d;
}
public String toString() {
return "(" + first + ", " + second + ", " +
third + ", " + fourth + ")" ;
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//: net/mindview/util/FiveTuple.java
package net.mindview.util;
public class FiveTuple<A,B,C,D,E>
extends FourTuple<A,B,C,D> {
public final E fifth;
public FiveTuple(A a, B b, C c, D d, E e) {
super (a, b, c, d);
fifth = e;
}
public String toString() {
return "(" + first + ", " + second + ", " +
third + ", " + fourth + ", " + fifth + ")" ;
}
}
|
为了使用元组,你只需定义一个长度适合的元组,将其作为方法的返回值,然后在return语句中创建该元组,并返回即可。
实例
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
|
//: generics/TupleTest.java
import net.mindview.util.*;
class Amphibian {
}
class Vehicle {
}
public class TupleTest {
static TwoTuple<String, Integer> f() {
// Autoboxing converts the int to Integer:
return new TwoTuple<String, Integer>( "hi" , 47 );
}
static ThreeTuple<Amphibian, String, Integer> g() {
return new ThreeTuple<Amphibian, String, Integer>( new Amphibian(), "hi" ,
47 );
}
static FourTuple<Vehicle, Amphibian, String, Integer> h() {
return new FourTuple<Vehicle, Amphibian, String, Integer>( new Vehicle(),
new Amphibian(), "hi" , 47 );
}
static FiveTuple<Vehicle, Amphibian, String, Integer, Double> k() {
return new FiveTuple<Vehicle, Amphibian, String, Integer, Double>(
new Vehicle(), new Amphibian(), "hi" , 47 , 11.1 );
}
public static void main(String[] args) {
TwoTuple<String, Integer> ttsi = f();
System.out.println(ttsi);
// ttsi.first = "there"; // Compile error: final
System.out.println(g());
System.out.println(h());
System.out.println(k());
}
}
|
输出结果:
(hi, 47)
(Amphibian@15db9742, hi, 47)
(Vehicle@6d06d69c, Amphibian@7852e922, hi, 47)
(Vehicle@4e25154f, Amphibian@70dea4e, hi, 47, 11.1)
由于有了泛型,你可以很容易地创建元组,令其返回一组任意类型的对象。而你所要做的,只是编写表达式而已。
通过ttsi.first = "there";语句的错误,我们可以看出,final声明确实能够保护public元素,在对象被构造出来之后,声明为final的元素便不能被再赋予其他值了。
java return返回多个值或多种类型的值方法(list;Map)
1、在写方法的时候
有时候需要返回多个值,有时候返回的多个值的类型还不同,依据不同情况以下提供了三种方法返回多个值。
2、具体思路都在代码注释里了
如果返回的多个值类型相同,可以用方法一和方法二;如果返回的多个值类型不同,可以用方法三。
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
import java.util.*;
public class Demo {
//方法1:返回list
public static List< int []> returnList(){
List< int []> list= new ArrayList<>();
list.add( new int []{ 1 });
list.add( new int []{ 1 , 2 });
list.add( new int []{ 1 , 2 , 3 });
return list;
}
//方法2:返回Map,一个Map只能有一种数据类型
public static Map<String, Integer> returnMap(){
Map<String,Integer> map = new HashMap<>();
map.put( "age" , 1 ); //”age“是key,类似于索引,1是索引对应的int值
map.put( "high" , 30 );
//System.out.println(map.get("age"));
Map<String, int []> map1 = new HashMap<>();
map1.put( "array" , new int []{ 1 , 2 , 3 });
//System.out.println(Arrays.toString( map1.get("array") ));
return map;
}
//方法3:一次性返回两种类型的数据,结合了Map和list
public static List<Map> returnMapList(){
Map<String,Integer> map = new HashMap<>();
map.put( "age" , 1 );
map.put( "high" , 30 );
Map<String, int []> map1 = new HashMap<>();
map1.put( "array" , new int []{ 1 , 2 });
List<Map> listMap = new ArrayList<Map>();
listMap.add(map);
listMap.add(map1);
return listMap;
}
//测试代码
public static void main(String[] args){
//返回list
List< int []> list1 = returnList();
System.out.println(Arrays.toString(list1.get( 0 )) + Arrays.toString(list1.get( 1 )) + Arrays.toString(list1.get( 2 )) + "\nreturnlist结束\n" );
//返回Map,一个Map只能有一种数据类型
Map<String,Integer> mapTest = returnMap();
System.out.println( "age = " + mapTest.get( "age" ) + ", high = " + mapTest.get( "high" ) + "\nreturnMap结束\n" );
//一次性返回两种类型的数据,结合了Map和list
List<Map> list2 = returnMapList();
System.out.println(list2.get( 0 ) + " , " + list2.get( 1 ) + "\nreturnMapList结束" ); //list2.get(1)是数组的地址
System.out.print( "调用返回的int和int[]:" );
Map map0 = list2.get( 0 );
Map map1 = list2.get( 1 );
System.out.println( "age = " + map0.get( "age" ) );
System.out.println( "array = " + Arrays.toString(( int []) map1.get( "array" )));
// System.out.println(Arrays.toString((int[]) list2.get(1).get("array"))); //调用过程也可以这样写
}
}
|
以上为个人经验,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://fanxiaobin.blog.csdn.net/article/details/53434752