Javaの异常、断言、泛型、日志
1.异常
什么是异常
- 异常,就是不正常的意思。指的是程序在执行过程中,出现的非正常的情况,最终会导致JVM的非正常停止。在Java等面向对象的编程语言中,异常本身是一个类,产生异常就是创建异常对象并抛出了一个异常对象。Java处理异常的方式是中断处理。注意:异常指的并不是语法错误,语法错了,编译不通过,不会产生字节码文件,根本不能运行.
异常体系
- 异常机制其实是帮助我们找到程序中的问题,异常的根类是 java.lang.Throwable ,其下有两个子类:java.lang.Error 与 java.lang.Exception ,平常所说的异常指 java.lang.Exception 。
Throwable体系:
Error:严重错误Error,无法通过处理的错误,只能事先避免,好比绝症。
Exception:表示异常,异常产生后程序员可以通过代码的方式纠正,使程序继续运行,是必须要处理的。好比感冒、阑尾炎。
Throwable中的常用方法:
public void printStackTrace() :打印异常的详细信息。包含了异常的类型,异常的原因,还包括异常出现的位置,在开发和调试阶段,都得使用printStackTrace。
public String getMessage() :获取发生异常的原因。提示给用户的时候,就提示错误原因。
public String toString() :获取异常的类型和异常描述信息(不用)。
异常分类
我们平常说的异常就是指Exception,因为这类异常一旦出现,我们就要对代码进行更正,修复程序。
异常(Exception)的分类:根据在编译时期还是运行时期去检查异常?
编译时期异常:checked异常。在编译时期,就会检查,如果没有处理异常,则编译失败。(如日期格式化异常);
运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)。
- 常见异常:
异常处理
- 抛出异常throw
在java中,提供了一个throw关键字,它用来抛出一个指定的异常对象。那么,抛出一个异常具体如何操作呢?- 创建一个异常对象。封装一些提示信息(信息可以自己编写)。
- 需要将这个异常对象告知给调用者。怎么告知呢?怎么将这个异常对象传递到调用者处呢?通过关键字throw就可以完成。throw 异常对象。throw用在方法内,用来抛出一个异常对象,将这个异常对象传递到调用者处,并结束当前方法的执行。
- 抛出异常throw
代码演示:
public class ThrowDemo {
public static void main(String[] args) {
//创建一个数组
int[] arr = {2,4,52,2};
//根据索引找对应的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*
* 根据 索引找到数组中对应的元素
*/
public static int getElement(int[] arr,int index){
//判断 索引是否越界
if(index<0 || index>arr.length‐1){
/*
判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
}
int element = arr[index];
return element;
}
}
如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是将问题返回给该方法的调用者。
那么对于调用者来说,该怎么处理呢?一种是进行捕获处理,另一种就是继续讲问题声明出去,使用throws声明处理。
②声明异常throws
声明异常:将问题标识出来,报告给调用者。如果方法内通过throw抛出了编译时异常,而没有捕获处理(稍后讲解该方式),那么必须通过throws进行声明,让调用者去处理。
关键字throws运用于方法声明之上,用于表示当前方法不处理异常,而是提醒该方法的调用者来处理异常(抛出异常).
声明异常格式: 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
代码演示:
public class ThrowsDemo2 {
public static void main(String[] args) throws IOException {
read("a.txt");
}
public static void read(String path)throws FileNotFoundException, IOException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) {
throw new IOException();
}
}
}
③捕获异常try…catch
捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
捕获异常语法如下:
try{
//编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
代码演示:
public class TryCatchDemo {
public static void main(String[] args) {
try {// 当产生异常时,必须有处理方式。要么捕获,要么声明。
read("b.txt");
} catch (FileNotFoundException e) {// 括号中需要定义什么呢?
//try中抛出的是什么异常,在括号中就定义什么异常类型
System.out.println(e);
}
System.out.println("over");
}
/*
*
* 我们 当前的这个方法中 有异常 有编译期异常
*/
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
}
}
④多个异常捕获
try{
//编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。
⑤finally 代码块finally:有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。finally不能单独使用,必须和try配套使用。只有在try或者catch中调用退出JVM的相关方法时,finally才不会执行,否则finally绝对会执行。
5. 自定义异常1. 自定义一个编译期异常: 自定义类 并继承于 java.lang.Exception 。2. 自定义一个运行时期的异常类:自定义类 并继承于 java.lang.RuntimeException 。
* 演示
// 业务逻辑异常
public class LoginException extends Exception {
/**
* 空参构造
*/
public LoginException() {
}
/**
*
* @param message 表示异常提示
*/
public LoginException(String message) {
super(message);
}
}
public class Demo {
// 模拟数据库中已存在账号
private static String[] names = {"bill","hill","jill"};
public static void main(String[] args) {
//调用方法
try{
// 可能出现异常的代码
checkUsername("nill");
System.out.println("注册成功");//如果没有异常就是注册成功
}catch(LoginException e){
//处理异常
e.printStackTrace();
}
}
//判断当前注册账号是否存在
//因为是编译期异常,又想调用者去处理 所以声明该异常
public static boolean checkUsername(String uname) throws LoginException{
for (String name : names) {
if(name.equals(uname)){//如果名字在这里面 就抛出登陆异常
throw new LoginException("亲"+name+"已经被注册了!");
}
}
return true;
}
}
2. 断言
1. 断言概述编写代码时,我们总是会做出一些假设,断言就是用于在代码中捕捉这些假设。可以将断言看作是异常处理的一种高级形式。断言表示为一些布尔表达式,程序员相信在程序中的某个特定点该表达式值为真。
2. 断言使用格式
1.assert 布尔表达式
2.assert 布尔表达式:消息
使用第一种格式,当布尔类型表达式为false时,抛出AssertionError异常;如果是第二种格式,则输出错误消息。
public class Test {
public static void main(String[] args) {
boolean isOk = 1 > 2;
//assert isOk;
assert isOk:"1不该大于2";
System.out.println("程序正常");
}
}
3. 断言的启用
在默认情况下idea中的断言不起作用,在idea等工具中可以开启和关闭断言功能:Run→Edit Configrations->在VM栏里输入-ea开启断言,输入-da关闭断言。
3.日志Logger
3.1 Logger
在Java中实现日志记录的方式有很多种,其中最简单的方式,就是System.out.print,System.err.print 这样直接在控制台打印消息了。接下来我们介绍的:java.util.logging.Logger是在JDK 1.4 版本之后加入的,提供了日志记录的API ,可以往控制台/文件中写日志了。
Logger 对象用来记录特定系统或应用程序组件的日志消息。一般使用圆点分隔的层次名称空间来命名 Logger。Logger 名称可以是任意的字符串,但是它们一般应该基于被记录组件的包名或类名,如 java.net 或 javax.swing。此外,可以创建“匿名”的 Logger,其名称未存储在 Logger 名称空间中。
可通过调用某个 getLogger 工厂方法来获得 Logger 对象。这些方法要么创建一个新 Logger,要么返回一个合适的现有 Logger。
日志消息被转发到已注册的 Handler 对象,该对象可以将消息转发到各种目的地,包括控制台、文件、OS 日志等等。
3.2 创建Logger对象
static Logger getLogger(String name) 为指定子系统查找或创建一个 logger。
Logger logger1 = Logger.getLogger(“com.suncaper.lxp.LogDemo”);
注意:name是Logger的名称,当名称相同时候,同一个名称的Logger只创建一个。
3.3 Logger的级别
类型 | 解释 |
---|---|
SEVERE | 严重 |
WARNING | 警告 |
INFO | 信息 |
CONFIG | 配置 |
FINE | 良好 |
FINER | 较好 |
FINEST | 最好 |
ALL | 开启所有级别的日志记录 |
OFF | 关闭所有级别的日志记录 |
logger默认的级别是INFO,比INFO更低的日志将不显示。
Logger的默认级别定义是在jre安装目录的lib下面的logging.properties。
可通过setLevel(Level.FINEST)方法改变级别。
public class Test {
public static void main(String[] args) throws IOException {
Logger log = Logger.getLogger("com");
log.setLevel(Level.FINEST);
}
}
3.4 Handler
Handler 对象从 Logger 中获取日志信息,并将这些信息导出。例如,它可将这些信息写入控制台或文件中,也可以将这些信息发送到网络日志服务中,或将其转发到操作系统日志中。可通过执行 setLevel(Level.OFF) 来禁用 Handler,并可通过执行适当级别的 setLevel 来重新启用。
//将日志打印至控制台
public class Test {
public static void main(String[] args) throws IOException {
Logger logger = Logger.getLogger("com.suncaper.test.LogDemo");
logger.setLevel(Level.ALL);
ConsoleHandler consoleHandler = new ConsoleHandler();
consoleHandler.setLevel(Level.FINEST);
logger.addHandler(consoleHandler);
logger.severe("严重");
logger.warning("警告");
logger.info("信息");
logger.config("配置");
logger.fine("良好");
logger.finer("较好");
logger.finest("最好");
}
}
//将日志写入文本
public class Test {
public static void main(String[] args) throws IOException {
Logger log = Logger.getLogger("com");
log.setLevel(Level.INFO);
Logger log1 = Logger.getLogger("com.suncaper");
ConsoleHandler consoleHandler =new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
log.addHandler(consoleHandler);
FileHandler fileHandler = new FileHandler("d://testlog.log");
fileHandler.setLevel(Level.INFO);
log.addHandler(fileHandler);
log.info("111");
log1.info("222");
log1.fine("333");
}
}
默认的日志方式是xml格式,很烂。所以最好自定义下logger的格式。需要用Formatter来定义。
3.5 Formatter
Formatter 为格式化 LogRecords 提供支持。
一般来说,每个日志记录 Handler 都有关联的 Formatter。Formatter 接受 LogRecord,并将它转换为一个字符串。默认设置即为:fileHandler.setFormatter(new XMLFormatter());可通过fileHandler.setFormatter(new SimpleFormatter())来修改日志记录的信息。
//将日志格式化写入文本
public class Test {
public static void main(String[] args) throws IOException {
Logger log = Logger.getLogger("com");
log.setLevel(Level.INFO);
Logger log1 = Logger.getLogger("com.suncaper");
ConsoleHandler consoleHandler =new ConsoleHandler();
consoleHandler.setLevel(Level.ALL);
log.addHandler(consoleHandler);
FileHandler fileHandler = new FileHandler("d://testlog.log");
fileHandler.setFormatter(new SimpleFormatter());
fileHandler.setLevel(Level.INFO);
log.addHandler(fileHandler);
log.info("111");
log1.info("222");
log1.fine("333");
}
}
4.泛型
- 泛型概述
- 泛型:就是一种不确定的数据类型。
- 反省的使用
- 定义和使用含有泛型的类
- 格式:修饰符calss 类名<代表泛型的变量> {}
- 含有泛型的方法
- 格式:修饰符 <代表泛型的变量> 返回值类型 方法名(参数){ }
- 演示:
- 定义和使用含有泛型的类
public class Person<T> {//定义泛型类
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
public <K> K hello(K k){//泛型方法1
return k;
}
public <K> void hello1(K k){//泛型方法2
System.out.println("泛型方法");
}
}
public class Test {
public static void main(String[] args) {
Person<String> p=new Person<>();
p.setT("hello");
System.out.println(p.getT());
p.hello("hello");//调用方法时,确定泛型的类型
p.hello(11);
}
}
3. 含有泛型的接口
格式:修饰符 interface 接口名 <代表泛型的变量>{}
1.定义子类时确定泛型的类型
public interface A<T> {//定义泛型接口A
void add(T t);
void del(T t);
}
public class B implements A<String> {//定义子类B实现泛型接口A
@Override
public void add(String s) {
}
@Override
public void del(String s) {
}
}
public class Test {//测试类
public static void main(String[] args) {
B b=new B();
b.add("hello");
}
}
2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型
public interface A<T> {//定义泛型接口A
void add(T t);
void del(T t);
}
public class B<T> implements A<T> {
@Override
public void add(T t) {
}
@Override
public void del(T t) {
}
}
public class Test {//测试类
public static void main(String[] args) {
B b=new B<String>();
b.add("hello");
}
}
- 泛型通配符
- 当使用泛型类或者接口时,传递的数据中,泛型类型不确定,可以通过通配符<?>表示。
public class Person<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class Test {
public static void main(String[] args) {
Person<String> p=new Person<>();
Person<Integer> p1=new Person<>();
ff2(p);
ff2(p1);
}
public static void ff2(Person<?> person){
}
}
在泛型中可以指定一个泛型的上限和下限。
泛型的上限:
格式: 类型名称 <? extends 类 > 对象名称
意义: 只能接收该类型及其子类
public class Person<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class Test {
public static void main(String[] args) {
Person<String> p=new Person<>();
Person<Integer> p1=new Person<>();
ff1(p);
ff1(p1);//报错
}
public static void ff1(Person<? extends String> person){
}
}
泛型的下限:
格式: 类型名称 <? super 类 > 对象名称
意义: 只能接收该类型及其父类型
public class Person<T> {
private T t;
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
public class Test {
public static void main(String[] args) {
Person<String> p=new Person<>();
Person<Integer> p1=new Person<>();
ff(p);
ff(p1);//报错
}
public static void ff(Person<? super String> person){
}
}
1.编写一个泛型方法,实现任意引用类型数组指定位置元素交换。
public static <T> T[] exchange(T[] a,int i,int j){
T temp = a[i];
a[i] = a[j];
a[j] = temp;
return a;
}
2.编写一个泛型方法,接收一个任意引用类型的数组,并反转数组中的所有元素。
public static <T> T[] turnOver(T[] a){
T temp;
for(int i = 0,j = a.length-1;i<j;i++,j--){
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
return a;
}
3.定义方法,遍历传递过来的任意引用类型数组。
public static <T> void traversal(T[] a){
for (int i = 0; i < a.length; i++) {
System.out.print(a[i] + " ");
}
System.out.println();
}
练习一:异常的体系
问题:
- 请描述异常的继承体系
- Throwable类是所有异常类的根类,所有的异常类都是由它继承
Exception类是程序员可以根据问题描述可以处理的
在Exception类中可以分为运行时异常和编译时异常,
编译时异常必须处理否则无法运行,
运行时异常就是编译通过,在运行时发生的异常
运行时异常在发生时会退出当前的方法
- Throwable类是所有异常类的根类,所有的异常类都是由它继承
- 请描述你对错误(Error)的理解
- Error:是严重错误,无法通过处理的错误,只能事先避免,不然的话程序无法运行
从Java设计的角度来讲,程序基本不可以通过后续代码修复,从而理应终止。当然,
从语法上来讲,所有这些都可以被写进catch里面,但是Error因为上述原因,不应该被代码处理。
- Error:是严重错误,无法通过处理的错误,只能事先避免,不然的话程序无法运行
- 请描述你对异常(Expection的理解)
- 从本质上来讲,java异常是一个java对象(继承Object),和一般的java对象一样,封装了一些成员变量和操作,我们可以向操作一般java对象那样去操作java异常对象(我还特地去试了试可不可以使用throw关键字操作一般的java对象,发现编译错误,证明它仅仅是操作异常类的语法)
- 从代表的含义上来说:java异常是一种错误情况,是程序不希望出现的现象,但是由于程序本身的设计逻辑和运行的环境等因素,出现异常的情况不可避免,java虚拟机针对不同的异常情况定义了很多异常类,当jvm运行程序发现对应的异常时,将会向外面抛出异常
- 请描述你对运行时异常(RuntimeException)的理解
- 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)。
该异常在编译通过之后运行程序时产生,运行时异常是不需要捕获的,程序员可以不去处理,当异常出现时,虚拟机会处理。常见的运行时异常有空指针异常。
- 运行时期异常:runtime异常。在运行时期,检查异常.在编译时期,运行异常不会编译器检测(不报错)。(如数学异常)。
练习二:throw与throws的区别
问题:
请描述throw的使用位置,作用是什么?
* throw的使用位置是在方法体内部,用于抛出异常。当方法
在执行过程中遇到异常情况时,将异常信息封装为异常对象,
然后throw
请描述throws的使用位置,作用是什么?
* throws出现在方法的声明中,表示该方法可能能会抛出的异
常,允许throws后面跟着多个异常类型
练习三:异常的处理方式
问题:
异常处理方式有几种,分别是什么?
共有五种:抛出异常throw,在方法体内部使用throw关键字抛出指定的异常对象
声明异常throws
- 在方法头部使用throws告知编译器此方法可能会抛出的异常
- 如果方法内通过throw抛出了编译时异常,而没有捕获处理
,那么必须通过throws进行声明,让调用者去处理。 - 声明异常格式: 修饰符 返回值类型 方法名(参数) throws 异常类名1,异常类名2…{ }
捕获异常try…catch
- 捕获异常:Java中对异常有针对性的语句进行捕获,可以对出现的异常进行指定方式的处理。
多个异常捕获
- 使用多个try…catch对异常进行捕获
finally代码块
- 有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些
语句执行不到。而finally就是解决这个问题的,在finally代码块中存放的代码都是一定会被执行的。
finally不能单独使用,必须和try配套使用。 - 只有在try或者catch中调用退出JVM的相关方法时,finally才不会执行,否则finally绝对会执行。
- 有一些特定的代码无论异常是否发生,都需要执行。另外,因为异常会引发程序跳转,导致有些
详细阐述每种方式对异常是如何处理的
- throw方式:
- 如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是
将问题返回给该方法的调用者。 - 先封装一些提示信息 再将异常告知程序的使用者
- 如果产生了问题,我们就会throw将问题描述类即异常进行抛出,也就是
例:
- throw方式:
public class ThrowDemo {
public static void main(String[] args) {
//创建一个数组
int[] arr = {2,4,52,2};
//根据索引找对应的元素
int index = 4;
int element = getElement(arr, index);
System.out.println(element);
System.out.println("over");
}
/*
* 根据 索引找到数组中对应的元素
*/
public static int getElement(int[] arr,int index){
//判断 索引是否越界
if(index<0 || index>arr.length‐1){
/*
判断条件如果满足,当执行完throw抛出异常对象后,方法已经无法继续运算。
这时就会结束当前方法的执行,并将异常告知给调用者。这时就需要通过异常来解决。
*/
throw new ArrayIndexOutOfBoundsException("哥们,角标越界了~~~");
}
int element = arr[index];
return element;
}
}
- throws方式
public class ThrowsDemo2 {
public static void main(String[] args) throws IOException {
read("a.txt");
}
public static void read(String path)throws FileNotFoundException, IOException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
if (!path.equals("b.txt")) {
throw new IOException();
}
}
}
- 捕获异常语法如下:
try{
//编写可能会出现异常的代码
}catch(异常类型 e){
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}
例:
public class TryCatchDemo {
public static void main(String[] args) {
try {// 当产生异常时,必须有处理方式。要么捕获,要么声明。
read("b.txt");
} catch (FileNotFoundException e) {// 括号中需要定义什么呢?
//try中抛出的是什么异常,在括号中就定义什么异常类型
System.out.println(e);
}
System.out.println("over");
}
/*
*
* 我们 当前的这个方法中 有异常 有编译期异常
*/
public static void read(String path) throws FileNotFoundException {
if (!path.equals("a.txt")) {//如果不是 a.txt这个文件
// 我假设 如果不是 a.txt 认为 该文件不存在 是一个错误 也就是异常 throw
throw new FileNotFoundException("文件不存在");
}
}
}
- 多个异常捕获实例
try{
//编写可能会出现异常的代码
}catch(异常类型A e){ 当try中出现A类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}catch(异常类型B e){ 当try中出现B类型异常,就用该catch来捕获.
处理异常的代码
//记录日志/打印异常信息/继续抛出异常
}finally{
//最后执行的代码
}
练习四:常见异常,及产生原因
问题:请列举常见异常7个,并说明产生原因。
答:
1. java.lang.nullpointerexception
空指针异常 简单地说就是调用了未经过初始化的对象或
者是不存在的对象,常出现在创建图片,调用数组这些操作中。
2. java.lang.arithmeticexception
这个异常就是数学运算异常,比如程序中出现了除以0的
这种运算
3. java.lang.arrayindexoutofboundsexception
这个异常就是数组下标越界,在调用数组时使用了比数
组本身大小更大的下标。
4. SQLException
操作数据库异常,这个异常是因为操作数据库异常,一般是数据库的操作不当导致的
5. FileNotFoundException
文件未找到异常,一般发生于文件操作时找不到目标路径的文件
6. java.lang.AbstractMethodError
抽象方法错误。当应用试图调用抽象方法时抛出。
7. java.lang.AssertionError
断言错。用来指示一个断言失败的情况
具体请见https://blog.csdn.net/yangzhengjianglove/article/details/81233784
练习五:自定义异常类
问题:
请使用代码实现每一个学生(Student)都有学号,姓名和分数,分数永远不能为负数如果老师给学生赋值一个负数,抛出一个自定异常
public class Demo5 {
static Scanner sc = new Scanner(System.in);
//请使用代码实现
//每一个学生(Student)都有学号,姓名和分数,分数永远不能为负数
//如果老师给学生赋值一个负数,抛出一个自定异常
public static void main(String[] args) {
Student student = new Student();
try {
checkStudentScore(student);
} catch (MyFirstException e) {
e.printStackTrace();
}
}
public static boolean checkStudentScore(Student student) throws MyFirstException{
System.out.print("请输入学生的姓名");
student.setName(sc.next());
System.out.println("请输入学生的学号");
student.setId(sc.next());
System.out.println("请输入学生的分数");
student.setScore(sc.nextInt());
if(student.getScore()<0){
throw new MyFirstException("分数能为负值吗?憨憨?");
}
return true;
}
}
public class Student {
private String id;
private String name;
private int score;
public Student() {
}
public Student(String id, String name, int score) {
this.id = id;
this.name = name;
this.score = score;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getScore() {
return score;
}
public void setScore(int score) {
this.score = score;
}
}