复习:
集合:
HashMap:
Hash表实现
数据结构
TreeMap:
排序map
客户端排序 :
手动编写比较器
Comparator接口
面向编程人员
自然排序:
类 实现 Comparable
在使用TreeXxx添加数据(类对象)的时候,
就会自动排序
面向设计人员
TreeSet
HashSet 和 HashMap 联系
HashSet中维护 一个HashMap
HashSet添加方法就是调用了HashMap的put方法
map.put(添加的数据,final new Object());
泛型 :
1,定义一个类型,进行占位
public <T,W> T show(T t){}
2,编译-->class 没有
反射 :
Student类加载的时候(class),
在堆中创建了一个Class类的对象
Class类的对象 : 有地址
Student类的所有属性
Student类的所有方法
这个地址会放到 方法区 student类一起
Student类的Class引用
获得 某一个类的Class引用
Class<Student> sc = Student.class;
Student s = new Student();
Class<Student> sc = s.getClass();
使用class对象获得 Student类的属性 和方法
// Field 属性
// Method 方法
Field = sc.getField("属性名");
public void show(int a,String b,dobule c){}
Method method = sc.getMethod("方法名",
int.class,String.class,dobule.class);
Object return =
method.invoke(Student类的某个对象,参数列表的值);
注解:
@Target
表示注解能写在什么上面。作用于哪里。
METHOD 可用于方法上
TYPE 可用于类或者接口上
FIELD 可用于属性上
PARAMETER 可用于参数上
CONSTRUCTOR 可用于构造方法上
ANNOTATION_TYPE 可用于注解类型上(被 @interface修饰的类型)
LOCAL_VARIABLE 可用于局部变量上
PACKAGE 用于记录java文件的package信息
@Retention 保留
定义了该Annotation被保留的时间长短
1,仅出现在源代码中,而被编译器丢弃
2,被编译在class文件中
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在运行时有效(即运行时保留)
@Documented 文档API
annotation应该被作为被标注的程序成员的公共API
@Inherited 被继承的
@Inherited阐述了某个被标注的类型是被继承的
@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类
自定义注解:
public @interface A {}
给注解定义属性:
权限 参数 属性名 默认 值
public String value() default "";
注:权限只有public 和 默认的
参数支持的数据类型:
基本数据类型
String类型
Class类型,可以添加泛型
以及上面的数组类型
可变参数 : 可以接受任意个同类型的数据。
13.1:语法: public void show(int... a);----> public void show(int[] a)
13.2:含义: 调用这个show方法的时候可以传入多个int数据
13.2.1: show(1); ---> show(new int[]{1});
13.2.2: show(1,2,3); ---> show(new int[]{1,2,3})
13.2.2: show(); ---> show(nnew int[0])
13.3:取值 可变参数有length属性.获取数组长度。-->取值同数组.
show(1,2,3,4);---->a[0],a[1],a[2],a[3]...
注意:可变参数一定是放在方法参数的最后一个。
eg: public void show(int a,String b,double... c){}
forEach循环:
14.1:语法 for(数据类型 变量 : 被遍历的数据){}
14.2:解释 : 使用 数据类型的变量来接收每次被遍历出来的数据
int[] arr = {1,2,4,5};
for(int num : arr){
System.out.println(num);
}
枚举类型 : 使用enum关键字枚举和类一个级别。
1,实例:
public enum Gender{
Man,WoMan;
}
public class Student{
int id;
String gender="男/女"
Gender gender;
public enum Gender{
M,W;
}
}
表示:一个枚举类Gender,有两个对象Man和WoMan。
注: 其中每一个枚举元素都是该枚举类型的一个实例
2,获取枚举类型中的对象:
1, Gender gender = Gender.Man;
2, Gender gender = Gender.WoMan;
3, for(Gender g : Gender.values()){
syso(g);//Man,WoMan
}
3,Enum类和enum关键字的区别
1.使用enum关键字定义的枚举类型,实际上就相当于定义了一个类,此类继承了java.lang.Enum类
2.每一个枚举值都是一个枚举类型的实例,它们被预设为public static final
Enum类的只有一个受保护的构造方法
protectd Enum(String name,int ordinal)
ordinal: 枚举元素的编号
实际上对于每一个枚举元素一旦声明之后,就表示自动调用此构造方法,所有的编号采用自动编号的方式进行(编号从0开始);
JDK1.5增加了枚举类型,可以使用enum来定义
使用valueOf()方法,通过枚举类可以找到枚举中一个指定的对象
public enum Color{
RED,BLUE;
}
获得枚举类型对象的俩种方式:
第一种方式:
String s = "RED";
Color red = Color.valueOf(s);
第二种方式:
Color red = Color.RED;
第一种方式是通过一个字符串的值来获得对象的,只要我们改变字符串的值就随意改变要获得的对象.
第二种方式就是写死的代码,不管怎么执行都是拿到枚举类中 RED对象,永远都是这样。
枚举类型的属性和方法
枚举类型可以有属性和方法
规则如下:
属性和方法必须定义在元素列表声明之后
public enum Color{
RED,BLUE;
private String name;
public String getName(){
return this.name;
}
}
枚举类型中定义构造方法
1.枚举的构造方法只能定义在元素列表之后
2.枚举类型的构造方法只能是private的,不写默认也是private
3.元素如果需要调用有参构造方法,则在元素后面加上"(参数)"
解释:Color类型只有三个固定对象,分别为RED GREEN BLUE,并且这个三个对象在创建的时候分别调用了有参的和无参的构造器
eg:
public enum Color {
RED("红色"),GREEN("绿色"),BLUE;
private String name;
public String getName(){
return this.name;
}
//一个参数构造器
Color(String name){
this.name = name;
}
//无参构造器
private Color(){
}
}
main:
//拿到Color中的三个固定对象的其中一个
Color c = Color.RED;
//拿到RED对象中的name属性的值
//这个值打印出来会是 "红色"
//因为是RED这个对象才创建的时候
//通过一个参数的构造器传给属性name的
//在枚举类型中声明元素列表其实就是
//在创建这个枚举类型的固定对象
String name = c.getName();
枚举隐式继承于Enum因此,无法再继承其他类
枚举实现接口
枚举可以实现接口,有以下两种方式
1.与普通class类一样,在枚举类中实现接口一样
2.枚举中单独实现接口中的抽象方法或者各个枚举元素对象中分别实现这个接口中的抽象方法
public interface Sofa{
void sit();
}
第一种方式来实现接口
public enum Color implements Sofa{
RED("红色"),GREEN("绿色"),BLUE;
private String name;
public String getName(){
return this.name;
}
//一个参数构造器
Color(String name){
this.name = name;
}
//无参构造器
private Color(){
}
//枚举中单独实现,每一个枚举元素对象都可以调用到这个方法
public void sit(){
//....
}
}
第二种方式来实现接口
public enum Color implements Sofa{
//每一个枚举元素对象中单独实现这个接口中的抽象方法 将来每个枚举元素对象调用到的就是自己独立实现的这个sit方法
RED("红色"){
public void sit(){
//....
}
},
GREEN("绿色"){
public void sit(){
//....
}
},
BLUE{
public void sit(){
//....
}
};
private String name;
public String getName(){
return this.name;
}
//一个参数构造器
Color(String name){
this.name = name;
}
//无参构造器
private Color(){
}
}
枚举中定义抽象方法
在一个枚举中可以定义多个抽象方法,但枚举中的每个元素必须分别实现这
些抽象方法
eg:
public enum Color {
RED{
public String getInfo() {
return "红色";
}
},
GREEN{
public String getInfo() {
return "绿色";
}
},
BLUE{
public String getInfo() {
return "蓝色";
}
};
public abstract String getInfo();
}
异常 Exception s
Java语言提供了一套完善的异常处理机制。正确运用这套机制,有助于提高程序的健壮性。
所谓程序的健壮性,指程序在多数情况下能够正常运行,返回预期的正确结果;
如果偶尔遇到异常情况,程序也可采取周到的解决措施。
Java语言按照面向对象的思想来处理异常,使得程序具有更好的可维护性。Java异常处理机制具有以下优点:
把各种不同类型的异常情况进行分类,用Java类来表示异常情况,这种类被称为异常类。
把异常情况表示成异常类,可以充分发挥类的可扩展和可重用的优势。
异常流程的代码和正常流程的代码分离,提高了程序的可读性,简化了程序的结构。
可以灵活地处理异常,如果当前方法有能力处理异常,就捕获并处理它,否则只需要抛出异常,由方法调用者来处理它。
异常是可以避免
数组下标越界
类型强制转换
知识点:一. 异常的基本概念
代码的意想不到的问题
1. 异常产生的条件
或者称为异常情况。在Java代码中哪些是异常情况呢? 例如:
a. 整数相除运算中,分母为0;
b. 通过一个没有指向任何具体对象的引用去访问对象的方法;
c. 使用数组长度作为下标访问数组元素;
d. 将一个引用强制转化成不相干的对象;
等等;
2. 异常会改变正常程序流程;
异常产生后,
正常的程序流程被打破了,
要么程序中止,
要么程序被转向异常处理的语句;
public double show(int 被除数,int 除数){
double 值= a/b;
syso(值)
{
预定义的解决方案
}
return 值
}
3. 当一个异常的事件发生后,该异常被虚拟机封装形成异常对象抛出。
4. 用来负责处理异常的代码被称为异常处理器
5. 通过异常处理器来捕获异常
二. try...catch语句
在Java语言中,用try...catch语句来捕获处理异常。格式如下:
try {
可能会出现异常情况的代码;
} catch(异常类型 异常参数) {
异常处理代码
} catch(异常类型 异常参数) {
异常处理代码
}final{
//一定会执行的代码
}
1. 如果try代码块中没有抛出异常,try代码块中语句会顺序执行完,catch代码块内容不会被执行;
2. 如果try代码块中抛出catch代码块所声明的异常类型对象,程序跳过try代码块中接下来代码,直接执行
catch代码块中对应内容;
a. 可以存在多个catch代码块,究竟执行哪个,看抛出的异常对象是否是catch代码块中异常类型;
b. 异常只能被一个异常处理器所处理, 不能声明两个异常处理器处理相同类型的异常;
c. 多个catch语句块所声明的异常类型不能越来越小;
d. 不能捕获一个在try语句块中没有抛出的异常;
3. 如果try代码块中抛出catch代码块未声明的异常类型对象,异常被抛给调用者;哪个调用了这段语句块
哪个负责处理这个异常;
4. 执行final中代码块
如果try或catch有return,而final中只是语句,没有return,那么在执行return语句的时候,会先进行标记,但不返回,等final中语句执行完毕后再返回,但返回的是return中标记好的那个值,不是final中修改的那个值。
三. 异常层级关系
所有异常类的祖先类为java.lang.Throwable类。它有两个直接的子类:
|Error
Throwable-- | |RuntimeException:
|Exception |
|Checked Exception:检查语法;
javac
1. Error类:表示仅靠程序本身无法恢复的严重错误,比如内存空间不足,或者Java虚拟机的方法调用栈溢出。在大多数情
况下,遇到这样的错误时,建议让程序终止。
2. Exception类:表示程序本身可以处理的异常。Exception还可以分为两种:运行时异常和受检查异常。
a. 运行时异常
1) 基本概念
RuntimeException类及其子类都被称为运行时异常,这种异常的特点是Java编译器不会检查它,也就是说,当程序中
可能出现这类异常时,即使没有用try...catch语句捕获它,也没有用throws子句声明抛出它,还是会编译通过。例
如divide()方法的参数b为0, 执行a/b操作时会出现ArithmeticException异常,它属于运行时异常,Java编译器不会
检查它。
public int divide(int a, int b) {
return a/b; //当参数b为0, 抛出ArithmeticException
}
2) 深入解析
运行时异常表示无法让程序恢复运行的异常,导致这种异常的原因通常是由于执行了错误操作。一旦出现了错误操作,
建议终止程序,因此Java编译器不检查这种异常。
运行时异常应该尽量避免。在程序调试阶段,遇到这种异常时,正确的做法是改进程序的设计和实现方式,修改程序
中的错误,从而避免这种异常。捕获它并且使程序恢复运行并不是明智的办法。
3) 对比
与Error类相比:
相同点:i. Java编译器都不会检查它们;
ii.当程序运行时出现它们, 都会终止程序;
不同点:i. Error类及其子类表示的错误通常是由Java虚拟机抛出的,在JDK中预定义了一些错误类,比如
OutOfMemoryError和StackOutofMemoryError。
RuntimeException表示程序代码中的错误;
ii.Error类一般不会扩展来创建用户自定义的错误类;
RuntimeException是可以扩展的,用户可以根据特定的问题领域来创建相关的运行时异常类;
b. 受检查异常(编译异常)
除了RuntimeException及其子类以外, 其他的Exception类及其子类都属于受检查异常(Checked Exception)。 这种
异常的特点是Java编译器会检查它,也就是说,当程序中可能出现这类异常时,要么用try...catch语句捕获它,要
么用throws子句声明抛出它,否则编译不会通过。
异常调用栈
异常处理时所经过的一系列方法调用过程被称为异常调用栈。
1. 异常的传播
哪个调用,哪个处理;
a. 异常情况发生后,发生异常所在的方法可以处理;
b. 异常所在的方法内部没有处理,该异常将被抛给该方法调用者,调用者可以处理;
c. 如调用者没有处理,异常将被继续抛出;如一直没有对异常处理,异常将被抛至虚拟机;
2. 如果异常没有被捕获,那么异常将使你的程序将被停止。
异常产生后,如果一直没有进行捕获处理,该异常被抛给虚拟机。程序将被终止。
3. 经常会使用的异常API
getMessage:获得具体的异常出错信息,可能为null。
printStatckTrace():打印异常在传播过程中所经过的一系列方法的信息,简称异常处理方法调用栈信息;在程序调试
阶段,此方法可用于跟踪错误。
四. 一些未检查的异常RuntimeException
1. java.lang.ArithmeticException
算术异常 如:除0;
2. java.lang.NullPointerException
空指针引用 如:没初始化一个References便使用;
3. java.lang.ArrayIndexoutofBoundsException
数组越界 如:调用一个有十个元素的Array的第十一个元素的内容;
4. java.lang.ClassCastException
强制类型转换异常
5. java.lang.NumberFormatException
数据格式异常 如:Integer.parseInt("a");
6. java.lang.NegativeArraySizeException 数组长度为负数异常
五. 异常声明和处理
1. 自己主动使用throw语句的时候代码会抛出异常;
2. 使用try-catch-finally语句结构处理或
在方法声明上声明throws继续抛出;
异常处理语句的语法规则:
1. try代码块不能脱离catch代码块或finally代码块而单独存在。try代码块后面至少有一个catch代码块或finally代码块。
2. try代码块后面可以有零个或多个catch代码块,还可以有零个或至多一个finally代码块。如果catch代码块和finally代码
块并存,finally代码块必须在catch代码块后面。
3. try代码块后面可以只跟finally代码块。
4. 在try代码块中定义的变量的作用域为try代码块,在catch代码块和finally代码块中不能访问该变量。
5. 当try代码块后面有多个catch代码块时,Java虚拟机会把实际抛出的异常对象依次和各个catch代码块声明的异常类型匹配,
如果异常对象为某个异常或其子类的实例,就执行这个catch代码块,而不会再执行其他的catch代码块。
6. 如果一个方法可能出现受检查异常,要么用try...catch语句捕获,要么用throws子句声明将它抛出。
7. throw语句后面不允许紧跟其它语句,因为这些语句永远不会被执行。
八. 编写/使用自己的异常类,
在特定的问题领域,可以通过扩展Exception类或RuntimeException类来创建自定义的异常。异常类包含了和异常相关的信息,
这有助于负责捕获异常的catch代码块,正确地分析并处理异常。
package com.briup.chap08;
public class UserException extends Exception{
public UserException() {
super();
}
public UserException(String message) {
super(message);
}
}
package com.briup.chap08;
public class UserExceptionTest {
public void addUser()throws UserException{
System.out.println("添加用户");
}
public static void main(String[] args) {
UserExceptionTest u = new UserExceptionTest();
try {
u.addUser();
} catch (UserException e) {
e.printStackTrace();
}
}
}
九. 断言
在Eclipse中使用断言:
window-->perference-->java-->installed JreS -->edit-->default Vm arguments : -ea
假设要进行如下的计算:
double y = Math.sqrt(x);
为了让程序健壮,你会先进行测试检查并抛出异常而不让x的值为负数。
if(x<0) throw new IllealArgumentException("x < 0");
但是,就算是测试结束了,以后实际运行时x的值不会小于0。这种测试代码会一直保留在你的程序中。如果程序中有太多的
检查,程序的运行就会慢好多。
如果在测试阶段会有这种检查,而在发布阶段能自动删除这些东西。该多好! 这就是断言机制。
1. 断言使用
在JDK1.4中,Java语言引入一个新的关键字: assert。 该关键字有两种形式:
assert 条件
以及
assert 条件: 表达式
这两种形式都会对条件进行评估,如果结果为假则抛出AssertionError。
在第二种形式中,表达式会传入AssertionError的
构造器并转成一个消息字符串。
表达式字符串部分的唯一目的就是生成一个消息字符串。
AssertionError对象并不存储表达式的值,因此你不可能在以后获取它。
要断言x不是负数,只需要使用如下简单的语句:
assert x >= 0;
或者你可以将x的值传递给AssertionError对象,从而可以在以后显示:
assert x >= 0 : x;
2. 断言内容代码编译
因为assert是一个新的关键字,因此在使用时需要告诉编译器你编译所使用jdk的版本号。
javac -source 1.4 MyClass.java
在jdk的后续版本中,对断言的支持成为默认特性(我们使用的是JDK5.0以上,使用不需要使用这个编译,默认就支持的)。
3. 断言内容代码执行
默认情况下,断言是关闭的。要通过-enableassertions或者-ea选项来运行程序以打开断言:
java -enableassertions com.briup.ch07.Xxxx
java -ea com.briup.ch07.Xxxx
打开或关闭断言是类装载器的功能。当断言功能被关闭时,类装载器会跳过那些和断言相关的代码,因此不会降低程序运行速度。
注意:使用eclipse运行代码的时候也是可以传参数的(包括俩种参数)
java -xx com.briup.ch07.Test yy
xx是给JVM传的参数 yy是给Test类的main方法传的参数