java 19-开发中各类小卡顿
1.jsonObject
JSONObject如何解析json数据
选取这段json数据是因为这段数据还是比较复杂的,能涵盖要说的关键点
{ "data": { "city": "深圳", "temphigh": "25", "templow": "19", "updatetime": "2017-11-04 13:23:00", "tempnow": "24", "sendibletemp": "27", "winddirect": "东北风", "windpower": "2级", "humidity": "42", "sunrise": "06:29", "sunset": "17:45", "weather": "多云", "week": "星期六", "nl": null, "date": "2017-11-04", "index": [ { "name": "化妆指数", "level": "控油", "msg": "建议用露质面霜打底,水质无油粉底霜,透明粉饼,粉质胭脂。" }, { "name": "感冒指数", "level": "易发", "msg": "感冒容易发生,少去人群密集的场所有利于降低感冒的几率。" }, { "name": "洗车指数", "level": "不宜", "msg": "雨(雪)水和泥水会弄脏您的爱车,不适宜清洗车辆。" }, { "name": "穿衣指数", "level": "舒适", "msg": "白天温度适中,但早晚凉,易穿脱的便携外套很实用。" }, { "name": "紫外线强度指数", "level": "弱", "msg": "辐射较弱,涂擦SPF12-15、PA+护肤品。" }, { "name": "运动指数", "level": "不适宜", "msg": "受到阵雨天气的影响,不宜在户外运动。" } ], "pm25": { "aqi": 0, "co": 8, "o3": 42, "pm10": 63, "pm2_5": 64, "quality": "良", "so2": 4, "no2": 11, "updatetime": "2017-11-04 13:00:00" }, "daily": [ { "date": "2017-11-04", "week": "星期六", "sunrise": "06:29", "sunset": "17:45", "temphigh": "25", "templow": "19", "weather": "多云" }, { "date": "2017-11-05", "week": "星期日", "sunrise": "06:29", "sunset": "17:45", "temphigh": "26", "templow": "19", "weather": "多云" }, { "date": "2017-11-06", "week": "星期一", "sunrise": "06:29", "sunset": "17:45", "temphigh": "27", "templow": "20", "weather": "多云" }, { "date": "2017-11-07", "week": "星期二", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "21", "weather": "多云" }, { "date": "2017-11-08", "week": "星期三", "sunrise": "06:29", "sunset": "17:45", "temphigh": "29", "templow": "22", "weather": "多云" }, { "date": "2017-11-09", "week": "星期四", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "22", "weather": "多云" }, { "date": "2017-11-03", "week": "星期五", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "18", "weather": "晴" } ] }, "status": 0, "msg": "ok" }
解析JSON
利用JSONString进行简单解析
我利用了RxVolley进行数据通信,t为API返回的数据
RxVolley.get("https://chkj02.market.alicloudapi.com/qgtq?city="+city, params, new HttpCallback() { @Override public void onSuccess(String t) { Loger.debug("请求到的数据:" + t); } });
我们现在要获取这部分数据,该如何进行解析呢?
首先,将t中的数据传到JSONObject
类型的jsonObject中,再通过getJSONObject
获取到data
下的数据。
//解析数据 JSONObject jsonObject = new JSONObject(t); JSONObject jsonData = jsonObject.getJSONObject("data");
此时,jsonData中数据为
{ "city": "深圳", "temphigh": "25", "templow": "19", "updatetime": "2017-11-04 13:23:00", "tempnow": "24", "sendibletemp": "27", "winddirect": "东北风", "windpower": "2级", "humidity": "42", "sunrise": "06:29", "sunset": "17:45", "weather": "多云", "week": "星期六", "nl": null, "date": "2017-11-04" }
然后通过getString
进行读值即可
//解析天气 String jsonTemplow = jsonData.getString("templow"); String jsonTempHigh = jsonData.getString("temphigh"); String jsonWeather = jsonData.getString("weather"); String jsonTempnow = jsonData.getString("tempnow"); String jsonWinddirect = jsonData.getString("winddirect"); String jsonWindpower = jsonData.getString("windpower"); String jsonHumidity = jsonData.getString("humidity");
利用JSONArray进行复杂解析
这次,我们要获取这部分数据
首先,将t中的数据传到JSONObject类型的jsonObject中,再通过getJSONObject
获取到data
下的数据。然后jsonArray通过getJSONArray
获得index
下的数据
//解析数据 JSONObject jsonObject = new JSONObject(t); JSONObject jsonData = jsonObject.getJSONObject("data"); JSONArray jsonIndex =jsonData.getJSONArray("index"); JSONArray jsonDaily =jsonData.getJSONArray("daily");
方法一
此时,jsonDaily中数据为
[ { "date": "2017-11-04", "week": "星期六", "sunrise": "06:29", "sunset": "17:45", "temphigh": "25", "templow": "19", "weather": "多云" }, { "date": "2017-11-05", "week": "星期日", "sunrise": "06:29", "sunset": "17:45", "temphigh": "26", "templow": "19", "weather": "多云" }, { "date": "2017-11-06", "week": "星期一", "sunrise": "06:29", "sunset": "17:45", "temphigh": "27", "templow": "20", "weather": "多云" }, { "date": "2017-11-07", "week": "星期二", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "21", "weather": "多云" }, { "date": "2017-11-08", "week": "星期三", "sunrise": "06:29", "sunset": "17:45", "temphigh": "29", "templow": "22", "weather": "多云" }, { "date": "2017-11-09", "week": "星期四", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "22", "weather": "多云" }, { "date": "2017-11-03", "week": "星期五", "sunrise": "06:29", "sunset": "17:45", "temphigh": "28", "templow": "18", "weather": "晴" } ]
把jsonDaily中按分类进行解析,分为几个ArrayList<>,dates
、weeks
、weathers
等,然后进行for循环。
List<String> dates = new ArrayList<>(); List<String> weeks = new ArrayList<>(); List<String> weathers = new ArrayList<>(); int j=1; for (int i=0;i<jsonDaily.length();i++){ JSONObject partDaily = jsonDaily.getJSONObject(i); JSONString date = partDaily.getString("date"); dates.add(date); JSONString week = partDaily.getString("week"); weeks.add(week); JSONString weather = partDaily.getString("weather"); weathers.add(weather); }
方法二
此时,jsonIndex中数据为
[ { "name": "化妆指数", "level": "控油", "msg": "建议用露质面霜打底,水质无油粉底霜,透明粉饼,粉质胭脂。" }, { "name": "感冒指数", "level": "易发", "msg": "感冒容易发生,少去人群密集的场所有利于降低感冒的几率。" }, { "name": "洗车指数", "level": "不宜", "msg": "雨(雪)水和泥水会弄脏您的爱车,不适宜清洗车辆。" }, { "name": "穿衣指数", "level": "舒适", "msg": "白天温度适中,但早晚凉,易穿脱的便携外套很实用。" }, { "name": "紫外线强度指数", "level": "弱", "msg": "辐射较弱,涂擦SPF12-15、PA+护肤品。" }, { "name": "运动指数", "level": "不适宜", "msg": "受到阵雨天气的影响,不宜在户外运动。" } ]
jsonIndex为二维数组,我们通过两个嵌套循环进行遍历。首先,外层根据数组长度进行for循环遍历;然后内层使用迭代器进行遍历。
String[] jsonIndex = new String[20];//数组长度声明为20确保够用 int j=1; for (int i=0;i<jsonArray.length();i++){ JSONObject partIndex =jsonIndex.getJSONObject(i); Iterator iterator = partIndex.keys(); String key; while(iterator.hasNext()){ //hasNext方法,只是判断下一个元素的有无,并不移动指针 key = (String) iterator.next();//next方法,向下移动指针,并且返回指针指向的元素,如果指针指向的内存中没有元素,会报异常 jsonIndex[j] = partIndex.getString(key); j++; } }
这样此指数数据就被我们成功解析,然后存入jsonIndex数组中。
2.Map
Map<String, String> 遍历的四种方法
Map<String, String> map = new HashMap<String, String>(); map.put("key1", "value1"); map.put("key2", "value2"); map.put("key3", "value3"); //第一种:普遍使用,二次取值 System.out.println("通过Map.keySet遍历key和value:"); for (String key : map.keySet()) { System.out.println("key= "+ key + " and value= " + map.get(key)); } //第二种 System.out.println("通过Map.entrySet使用iterator遍历key和value:"); Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第三种:推荐,尤其是容量大时 System.out.println("通过Map.entrySet遍历key和value"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第四种 System.out.println("通过Map.values()遍历所有的value,但不能遍历key"); for (String v : map.values()) { System.out.println("value= " + v); }
JSONObject和String相互转换
JSONObject jsonObject = new JSONObject(); JSONArray jsonArray = new JSONArray(); try { jsonObject.put("a","1"); jsonObject.put("b","2"); jsonObject.put("c","3"); jsonObject.put("d","4"); for(int i=0;i<10;i++){ JSONObject object = new JSONObject(); object.put("name",i+""); jsonArray.put(object); } jsonObject.put("abcd",jsonArray); } catch (JSONException e) { e.printStackTrace(); } Log.e("MainActivity",jsonObject.toString()); try { JSONObject object = new JSONObject(jsonObject.toString()); Log.e("MainActivity",object.toString()); } catch (JSONException e) { e.printStackTrace(); }
输出结果
11-13 14:14:13.846 15433-15433/com.example.apple.demo E/MainActivity:<br> {"a":"1","b":"2","c":"3","d":"4","abcd":[{"name":"0"},{"name":"1"},{"name":"2"},{"name":"3"},{"name":"4"},{"name":"5"},{"name":"6"},{"name":"7"},{"name":"8"},{"name":"9"}]} 11-13 14:14:13.846 15433-15433/com.example.apple.demo E/MainActivity: <br>{"a":"1","b":"2","c":"3","d":"4","abcd":[{"name":"0"},{"name":"1"},{"name":"2"},{"name":"3"},{"name":"4"},{"name":"5"},{"name":"6"},{"name":"7"},{"name":"8"},{"name":"9"}]}
JSONObject和Map相互转换,这个转换需要一个第三方的库文件,我比较喜欢用FastJson,具体使用请看我的另外一篇博客
HashMap<String,String>map = new HashMap<>(); map.put("a","1"); map.put("b","2"); map.put("c","3"); String json = JSON.toJSONString(map);//map转String JSONObject jsonObject = JSON.parseObject(json);//String转json //json转map Map<String, String> jsonMap = JSONObject.toJavaObject(jsonObject, Map.class); //String转map Map<String, String> jsonMap1 = JSONObject.parseObject(json, Map.class);
BaseResponse.class
package com.chenglulu.controller.users.domain; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import org.omg.CORBA.Any; @Data public class BaseResponse<T> { public BaseResponse() { super(); } private String requestId; private String message; private Integer code; private T data; public BaseResponse(String requestId, Integer code, String message, T data) { this.code = code; this.message = message; this.data = data; this.requestId = requestId; } }
ResponseUtil.class
package com.chenglulu.utils; import com.chenglulu.enums.ResponseEnum; import com.chenglulu.controller.users.domain.BaseResponse; public class ResponseUtil { /**成功且带数据**/ public static BaseResponse success(String requestId, Object object){ BaseResponse res = new BaseResponse(); res.setRequestId(requestId); res.setCode(ResponseEnum.SUCCESS.getCode()); res.setMessage(ResponseEnum.SUCCESS.getMessage()); res.setData(object); return res; } /**成功但不带数据**/ public static BaseResponse success(String requestId){ BaseResponse result = new BaseResponse(); res.setRequestId(requestId); return success(null); } /**失败**/ public static BaseResponse error(String requestId, Integer code,String msg){ BaseResponse result = new BaseResponse(); res.setRequestId(requestId); result.setCode(code); result.setMessage(msg); return result; } }
ResponseCodeEnum枚举类
package com.chenglulu.enums; public enum ResponseCodeEnum { //这里是可以自己定义的,方便与前端交互即可 UNKNOWN_ERROR(-1,"未知错误"), SUCCESS(10000,"成功"), USER_NOT_EXIST(1,"用户不存在"), USER_IS_EXISTS(2,"用户已存在"), DATA_IS_NULL(3,"数据为空"), ; private Integer code; private String message; ResponseCodeEnum(Integer code, String message){ this.code = code; this.message = message; } public Integer getCode(){ return code; } public String getMessage(){ return message; } }
使用示例
import com.chenglulu.utils.ResponseUtil; @RestController @RequestMapping( value = "/users") public class UsersController { @RequestMapping(value = "/list", method = RequestMethod.GET) public BaseResponse queryUsers(HttpServletRequest request){ String requestId = request.getHeader("X-REQUEST-ID"); List<Users> usersList = []; return ResponseUtil.success(requestId, usersList); } }
4.TODO
刚好看到阿里巴巴开发规范的对于TODO的说明,粘贴出来有需要的可以参考
【参考】特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫描, 经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
1) 待办事宜(TODO):( 标记人,标记时间,[预计处理时间]) 表示需要实现,但目前还未实现的功能。 这实际上是一个 Javadoc 的标签,目前的 Javadoc 还没有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。
2) 错误,不能工作(FIXME):(标记人,标记时间,[预计处理时间]) 在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况
需要阿里巴巴Java开发手册(1.4.0版本)以及插件 可以去官方的GitHub上下载:https://github.com/alibaba/p3c
其实就是类似于标记的作用,可以很快的定位到这个位置,方便查找,如图:
5.lambada表达式
Lambda 表达式,也可称为闭包,它是推动 Java 8 发布的最重要新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。使用 Lambda 表达式可以使代码变的更加简洁紧凑。
(parameters) -> expression 或 (parameters) ->{ statements; }
以下是lambda表达式的重要特征:
- 可选类型声明:不需要声明参数类型,编译器可以统一识别参数值。
- 可选的参数圆括号:一个参数无需定义圆括号,但多个参数需要定义圆括号。
- 可选的大括号:如果主体包含了一个语句,就不需要使用大括号。
- 可选的返回关键字:如果主体只有一个表达式返回值则编译器会自动返回值,大括号需要指定明表达式返回了一个数值。
Lambda 表达式实例
// 1. 不需要参数,返回值为 5 () -> 5 // 2. 接收一个参数(数字类型),返回其2倍的值 x -> 2 * x // 3. 接受2个参数(数字),并返回他们的差值 (x, y) -> x – y // 4. 接收2个int型整数,返回他们的和 (int x, int y) -> x + y // 5. 接受一个 string 对象,并在控制台打印,不返回任何值(看起来像是返回void) (String s) -> System.out.print(s)
在 Java8Tester.java 文件输入以下代码:
public class Java8Tester { public static void main(String args[]){ Java8Tester tester = new Java8Tester(); // 类型声明 MathOperation addition = (int a, int b) -> a + b; // 不用类型声明 MathOperation subtraction = (a, b) -> a - b; // 大括号中的返回语句 MathOperation multiplication = (int a, int b) -> { return a * b; }; // 没有大括号及返回语句 MathOperation division = (int a, int b) -> a / b; System.out.println("10 + 5 = " + tester.operate(10, 5, addition)); System.out.println("10 - 5 = " + tester.operate(10, 5, subtraction)); System.out.println("10 x 5 = " + tester.operate(10, 5, multiplication)); System.out.println("10 / 5 = " + tester.operate(10, 5, division)); // 不用括号 GreetingService greetService1 = message -> System.out.println("Hello " + message); // 用括号 GreetingService greetService2 = (message) -> System.out.println("Hello " + message); greetService1.sayMessage("Runoob"); greetService2.sayMessage("Google"); } interface MathOperation { int operation(int a, int b); } interface GreetingService { void sayMessage(String message); } private int operate(int a, int b, MathOperation mathOperation){ return mathOperation.operation(a, b); } }
6.设计模式之 建造者模式 Builder pattern
在软件工程领域,设计模式是一套通用的可复用的解决方案,用来解决在软件设计过程中产生的通用问题。它不是一个可以直接转换成源代码的设计,只是一套在软件系统设计过程中程序员应该遵循的最佳实践准则。工作中常常出现建造者模式的身影,所以整理记录一下,希望对自己和其他人都有一个帮助。希望你读完本文后可以在实际开发过程中用上Builder 模式,成功装一把逼,书生我就甚是欣慰了。Builder pattern将一个复杂对象的构建与其表示分离,使得同样的构建过程可以创建不同的表示
当一个类的构造函数参数个数超过4个,而且这些参数有些是可选的参数,考虑使用构造者模式。
解决的问题
当一个类的构造函数参数超过4个,而且这些参数有些是可选的时,我们通常有两种办法来构建它的对象。 例如我们现在有如下一个类计算机类Computer
,其中cpu与ram是必填参数,而其他3个是可选参数,那么我们如何构造这个类的实例呢,通常有两种常用的方式:
public class Computer { private String cpu;//必须 private String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选 }
public class Computer { ... public Computer(String cpu, String ram) { this(cpu, ram, 0); } public Computer(String cpu, String ram, int usbCount) { this(cpu, ram, usbCount, "罗技键盘"); } public Computer(String cpu, String ram, int usbCount, String keyboard) { this(cpu, ram, usbCount, keyboard, "三星显示器"); } public Computer(String cpu, String ram, int usbCount, String keyboard, String display) { this.cpu = cpu; this.ram = ram; this.usbCount = usbCount; this.keyboard = keyboard; this.display = display; } }
public class Computer { ... public String getCpu() { return cpu; } public void setCpu(String cpu) { this.cpu = cpu; } public String getRam() { return ram; } public void setRam(String ram) { this.ram = ram; } public int getUsbCount() { return usbCount; } ... }
那么这两种方式有什么弊端呢?
第一种主要是使用及阅读不方便。你可以想象一下,当你要调用一个类的构造函数时,你首先要决定使用哪一个,然后里面又是一堆参数,如果这些参数的类型很多又都一样,你还要搞清楚这些参数的含义,很容易就传混了。。。那酸爽谁用谁知道。
第二种方式在构建过程中对象的状态容易发生变化,造成错误。因为那个类中的属性是分步设置的,所以就容易出错。
为了解决这两个痛点,builder模式就横空出世了。
如何实现
- 在Computer 中创建一个静态内部类 Builder,然后将Computer 中的参数都复制到Builder类中。
- 在Computer中创建一个private的构造函数,参数为Builder类型
- 在Builder中创建一个
public
的构造函数,参数为Computer中必填的那些参数,cpu 和ram。 - 在Builder中创建设置函数,对Computer中那些可选参数进行赋值,返回值为Builder类型的实例
- 在Builder中创建一个
build()
方法,在其中构建Computer的实例并返回
下面代码就是最终的样子
public class Computer { private final String cpu;//必须 private final String ram;//必须 private final int usbCount;//可选 private final String keyboard;//可选 private final String display;//可选 private Computer(Builder builder){ this.cpu=builder.cpu; this.ram=builder.ram; this.usbCount=builder.usbCount; this.keyboard=builder.keyboard; this.display=builder.display; } public static class Builder{ private String cpu;//必须 private String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选 public Builder(String cup,String ram){ this.cpu=cup; this.ram=ram; } public Builder setUsbCount(int usbCount) { this.usbCount = usbCount; return this; } public Builder setKeyboard(String keyboard) { this.keyboard = keyboard; return this; } public Builder setDisplay(String display) { this.display = display; return this; } public Computer build(){ return new Computer(this); } } //省略getter方法 }
如何使用
在客户端使用链式调用,一步一步的把对象构建出来。
Computer computer=new Computer.Builder("因特尔","三星") .setDisplay("三星24寸") .setKeyboard("罗技") .setUsbCount(2) .build();
案例
构建者模式是一个非常实用而常见的创建类型的模式(creational design pattern),例如图片处理框架Glide,网络请求框架Retrofit等都使用了此模式。
扩展
其实上面的内容是Builder在Java中一种简化的使用方式,经典的Builder 模式与其有一定的不同,如果没有兴趣的同学就可以不用往下读了。
传统Builder 模式
构建者模式UML图如下所示
如上图所示,builder模式有4个角色。
- Product: 最终要生成的对象,例如 Computer实例。
- Builder: 构建者的抽象基类(有时会使用接口代替)。其定义了构建Product的抽象步骤,其实体类需要实现这些步骤。其会包含一个用来返回最终产品的方法
Product getProduct()
。 - ConcreteBuilder: Builder的实现类。
- Director: 决定如何构建最终产品的算法. 其会包含一个负责组装的方法
void Construct(Builder builder)
, 在这个方法中通过调用builder的方法,就可以设置builder,等设置完成后,就可以通过builder的getProduct()
方法获得最终的产品。
我们接下来将最开始的例子使用传统方式来实现一遍。
第一步:我们的目标Computer类:
public class Computer { private String cpu;//必须 private String ram;//必须 private int usbCount;//可选 private String keyboard;//可选 private String display;//可选 public Computer(String cpu, String ram) { this.cpu = cpu; this.ram = ram; } public void setUsbCount(int usbCount) { this.usbCount = usbCount; } public void setKeyboard(String keyboard) { this.keyboard = keyboard; } public void setDisplay(String display) { this.display = display; } @Override public String toString() { return "Computer{" + "cpu='" + cpu + '\'' + ", ram='" + ram + '\'' + ", usbCount=" + usbCount + ", keyboard='" + keyboard + '\'' + ", display='" + display + '\'' + '}'; } }
第二步:抽象构建者类
public abstract class ComputerBuilder { public abstract void setUsbCount(); public abstract void setKeyboard(); public abstract void setDisplay(); public abstract Computer getComputer(); }
第三步:实体构建者类,我们可以根据要构建的产品种类产生多了实体构建者类,这里我们需要构建两种品牌的电脑,苹果电脑和联想电脑,所以我们生成了两个实体构建者类。
苹果电脑构建者类
public class MacComputerBuilder extends ComputerBuilder { private Computer computer; public MacComputerBuilder(String cpu, String ram) { computer = new Computer(cpu, ram); } @Override public void setUsbCount() { computer.setUsbCount(2); } @Override public void setKeyboard() { computer.setKeyboard("苹果键盘"); } @Override public void setDisplay() { computer.setDisplay("苹果显示器"); } @Override public Computer getComputer() { return computer; } }
联想电脑构建者类
public class LenovoComputerBuilder extends ComputerBuilder { private Computer computer; public LenovoComputerBuilder(String cpu, String ram) { computer=new Computer(cpu,ram); } @Override public void setUsbCount() { computer.setUsbCount(4); } @Override public void setKeyboard() { computer.setKeyboard("联想键盘"); } @Override public void setDisplay() { computer.setDisplay("联想显示器"); } @Override public Computer getComputer() { return computer; } }
第四步:指导者类(Director)
public class ComputerDirector { public void makeComputer(ComputerBuilder builder){ builder.setUsbCount(); builder.setDisplay(); builder.setKeyboard(); } }
使用
首先生成一个director (1),然后生成一个目标builder (2),接着使用director组装builder (3),组装完毕后使用builder创建产品实例 (4)。
public static void main(String[] args) { ComputerDirector director=new ComputerDirector();//1 ComputerBuilder builder=new MacComputerBuilder("I5处理器","三星125");//2 director.makeComputer(builder);//3 Computer macComputer=builder.getComputer();//4 System.out.println("mac computer:"+macComputer.toString()); ComputerBuilder lenovoBuilder=new LenovoComputerBuilder("I7处理器","海力士222"); director.makeComputer(lenovoBuilder); Computer lenovoComputer=lenovoBuilder.getComputer(); System.out.println("lenovo computer:"+lenovoComputer.toString()); }
输出结果如下:
mac computer:Computer{cpu='I5处理器', ram='三星125', usbCount=2, keyboard='苹果键盘', display='苹果显示器'} lenovo computer:Computer{cpu='I7处理器', ram='海力士222', usbCount=4, keyboard='联想键盘', display='联想显示器'}