1.当eclipse项目改变了编译配置(项目右键属性Properties->Java Compiler),用了高版本的编译器编译,则用低版本的JVM运行会报错,弹窗JVM启动警告Could not find the main class.Program will exit,报class文件的版本号错误java.lang.UnsupportedClassVersionError:Bad version number in .class file。
解决办法:
降低编译器版本。
升高运行版本。(项目右键属性Properties->Java Build Path->Libraries添加高版本jre)
2.断点:
F5:step into 跳入
F6:step over 跳过
F7:step return跳出
drop to frame:跳到当前方法的第一行
resume:跳到下一个断点(如果没有下一个,则运行完整个程序)
右键watch:观察变量或表达式的值
断点注意的问题:
1.断点调试完成后,要在breakpoints视图中清除所有断点
2.断点调试完成后,一定要记得结束运行断点的jvm
3.常用快捷键:
ctrl + shift + L : 查看所有快捷键
alt + / : 内容助理
ctrl + 1: 快速修复
ctrl + shift +o : 导包
ctrl + shift +F : 格式化代码块
ctrl + 左键 / F3:查看代码中存在方法,类的源代码
ctrl + shirt + T :查看指定类的源代码
Alt + 左/右:查看源代码的时候,回到上一步/下一步
ctrl + shift + / : 添加注释 /**/
ctrl + shift + \: 除去注释 /**/
F2 :查看方法说明
重置透视图(windows save/reset)
ctrl + shift + X :大写
ctrl + shift + Y :小写
ctrl + alt + 向上/下键:复制行
alt + 向上/下键:移动行
ctrl + T : 查看继承关系
ctrl +m : 窗口最大化/还原
ctrl +f :查找替换
ctrl + shift + L 查看所有快捷键
4.junit测试框架:在测试方法前加@Test
1.每个测试方法之前都运行:(常用)
@Before + 方法前: 初始化资源
@After + 方法前: 释放资源
2.类加载的时候运行,只运行一次: 方法必须设置静态static的
@BeforeClass + 方法前:作用同上
@AfterClass + 方法前:
3.断言类:判断返回值
import static org.junit.Assert.*;
assertEquals("返回值错误!","2", p.run());
5.JDK1.5新特性:
1.静态导入:导入类的静态成员,方便程序简化书写。
2.自动装箱拆箱:
int num = 4;
num = num + 5;
Integer i =4; //等效,Integer i = new Integer(4); 自动装箱,就是简化书写。
//自动装箱和不同赋值相比,多了一个空null。
//所以要先判断是否为null。因为空类型在拆箱的时候会报空指针异常。
i = i + 6; //等效i = new Integer(i.intValue() + 6); 自动装箱,拆箱(i.intValue())。
show(55);
public static void show(Object a){ //Object a = new Ingeter(55); 装箱,多态
}
面试:自定装箱,如果装箱的是一个字节,那么该数据会被共享,不会重新开辟空间。
Integer a = new Integer(127);
Integer b = new Integer(127);
System.out.println(a==b); //false
System.out.println(a.equals(b)); //true
Integer x = 127;
Integer y = 127;
System.out.println(x==y); //true, 自定装箱,如果装箱的是一个字节,那么该数据会被共享,不会重新开辟空间。
System.out.println(x.equals(y)); //true
public class Demo1 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
list.add(127); //装箱
list.add(127);
Iterator<Integer> it = list.iterator();
while(it.hasNext()){
System.out.println(it.next()==it.next()); //true,超过一个字节就是false
}
}
}
3.增强for循环
JDK1.5给Collection接口找了个父接口Iterable,实现这个接口允许对象成为 “foreach” 语句的目标。
foreach语句:底层还是实现的迭代。
格式:
for(类型 变量: Collection集合|数组)
{
}
传统for和高级for的区别:
foreach局限性:
必须有遍历的目标(数组或Collection单列集合),一般只用于遍历,不会对元素进行过多的操作。是用来简化书写的。
传统for循环相对foreach的优势:
可以定义控制循环的条件和增量。
使用场景:
对数组的遍历如果仅仅是获取数组中的元素,可以使用foerach。
如果要对数组的角标进行操作建议使用传统for。
对于map集合,不能直接使用foreach遍历。但是可以将map转换成单列的set,就可以用了。
例子:
public static void main(String[] args) {
Map<String,Integer> map = new HashMap<String,Integer>();
map.put("小米", 2000);
map.put("苹果", 5000);
map.put("三星", 4000);
//entrySet:
Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); //map变成set集合
for (Map.Entry<String, Integer> entry : entrySet) { //foreach遍历
System.out.println(entry.getKey() + ":" +entry.getValue());
}
//keySet:
for(String key : map.keySet()){
Integer value = map.get(key);
System.out.println(key + ": " + value);
}
//传统迭代:
Iterator<Map.Entry<String,Integer>> it= map.entrySet().iterator();
while(it.hasNext()){
Map.Entry<String, Integer> me = it.next();
System.out.println(me.getKey() + ":" + me.getValue());
}
}
4.可变参数:int …
内部执行的动作:创建并将参数封装成数组。
其实就是一个数组,但是接收的是数组的元素。
自动将这些元素封装成数组。简化了调用者的书写。
注意事项:可变参数类型必须定义在参数列表的结尾处。
//求多个正数的和
public static void main(String[] args){
int sum = add(2,5,6,6);
System.out.println("sum= " + sum);
int sum1 = add(2,5,6);
System.out.println("sum1= " + sum1);
}
public static int add(int... arr){ //int... 和int[]等效,简化书写。调用传参的时候不需要建立数组,直接传值。
int sum = 0;
for(int i:arr)
sum+=i;
return sum;
}
5.枚举类:
1.作用:一些程序在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,jdk5以前用自定义类来解决,jdk5以后可以直接采用枚举类解决。
2.用enum关键字定义一个枚举类。
3.一个枚举也可以用构造函数,字段,和方法。
4.示例:
public class Demo1 {
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
}
}
/*class Grade{
private Grade(){}
public static final Grade A =new Grade();
public static final Grade B =new Grade();
public static final Grade C =new Grade();
public static final Grade D =new Grade();
public static final Grade E =new Grade();
}*/
//等效于
enum Grade{ //class
A,B,C,D,E; //Object
}
5.定义枚举的构造方法,方法,和字段:
public class Demo1 {
@Test
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
String value = g.getValue();
System.out.println(value);
}
}
/*class Grade{
private Grade(){}
public static final Grade A =new Grade();
public static final Grade B =new Grade();
public static final Grade C =new Grade();
}*/
//等效于
//如何定义枚举的构造方法,方法,和字段去封装更对的信息
enum Grade{ //class A 100-90 B 89-80 C 79-70
A("100-90"),B("89-80"),C("79-70"); //Object
private String value; //封装每个对象对应的分数
private Grade(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
}
6.带抽象方法的枚举:
public class Demo1 {
@Test
public void test(){
print(Grade.B);
}
public void print(Grade g){ //A B C D E
String value = g.getValue();
String lValue = g.localeValue();
System.out.println(value + "("+lValue+")");
}
}
//带抽象方法的枚举
enum Grade{ //class A 100-90 优 B 89-80良 C 79-70一般
A("100-90"){
public String localeValue(){
return "优";
}
}
,B("89-80"){
public String localeValue(){
return "良";
}
}
,C("79-70"){ //Object
public String localeValue(){
return "一般";
}
};
private String value; //封装每个对象对应的分数
private Grade(String value){
this.value = value;
}
public String getValue(){
return this.value;
}
public abstract String localeValue();
}
7.枚举的常用方法和其他细节:
①枚举类也是一种特殊形式的Java类
②枚举类中声明的每一个枚举值代表枚举类的一个示例对象。
③与java中的普通类一样,在声明枚举类时,也可以声明属性,方法和构造函数,但枚举类的构造函数必须为私有的。
④枚举类也可以实现接口,或继承抽象类。
⑤JDK5中还扩展了switch语句,它除了可以接收int,byte,cher,short外,还可以接收一个枚举类型。
⑥若枚举类只有一个枚举值,则可以当作单态设计模式使用。
Java中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法。常用方法:
name()返回此枚举常量的名称,在其枚举声明中对其进行声明。
ordinal()返回枚举常量的序数(它在枚举声明中的位置,其中初始常量序数为零)。 大多数程序员不会使用此方法。它被设计用于复杂的基于枚举的数据结构,比如 EnumSet 和 EnumMap。
valueOf(Class enumClass, String name) 返回带指定名称的指定枚举类型的枚举常量。如果不存在字符串对应的枚举,就会报错。用于判断用户提交的字符串是否是枚举。
values()此方法虽然在在JDK文档中查找不到,但每个枚举类都具有该方法,它用于遍历枚举的所有枚举值。
//测试枚举的常用方法
@Test
public void test2(){
System.out.println(Grade.A.name());
System.out.println(Grade.A.ordinal());
String str = "B";
// Grade g = Grade.valueOf(Grade.class,str);
Grade g = Grade.valueOf(str);
System.out.println(g);
Grade gs[] = Grade.values();
for(Grade gg : gs){
System.out.print(gg);
}
}
6.反射技术:
1.一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。
2.什么情况下需要加载类,并解剖出类的各个组成部分:
加载类:
1.java中有一个Class类用于代表某一个类的字节码。
2.Class类既然代表某个类的字节码,它当然就是要提供加载某个类字节码的方法:forName()。
forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装。
static Class<?> forName(String name, boolean initialize, ClassLoader loader)
使用给定的类加载器,返回与带有给定字符串名的类或接口相关联的 Class 对象。
3.另外两种得到class对象的方式:
类名.class
对象.getClass()
public class Demo2 {
/*
反射:加载类,获得类是字节码
*/
public static void main(String[] args) throws ClassNotFoundException {
//1.
Class clazz = Class.forName("/myday01/src/cn/itcast/eclipse/Person");
//2.
Class clazz1 = new Person().getClass();
//3.
Class clazz2 = Person.class;
}
}
解剖类:
1.Class对象提供了如下常用方法:
①返回public的成员
Constructor<T> getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
Method getMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
Field getField(String name)
返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
②返回类声明的所有成员
Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
Field getDeclaredField(String name)
返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
2.这些方法分别用于从类中解剖出构造函数,方法和成员变量。解剖出的成员分别用Constructor,Method,Field对象表示。
3.如果你是一个框架的设计者,解剖出这些成员后你会干什么:
使用。
反射类的构造函数:
利用Constructor创建对象
1.Constructor类提供了如下方法,用于创建类的对象。
T newInstance(Object... initargs)
使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
initargs用于指定构造函数接收的参数。
2.练习:反射类无参,有参,私有的构造函数,创建类的对象。
另:
class对象中也有一个newInstance()方法,用于创建类的对象。这样开发人员可以避免每次都需要反射Constructor类以创建对象。
但是需要注意的是:class.newInstance()方法内部是反射类无参的构造函数创建的对象,所以用此种方式创建类对象时,类必须有一个无参的构造函数。
示例:
//反射类的构造函数,创建类的对象
public class Demo2 {
//反射构造函数:public Person()
@Test
public void test1() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(null);
Person p = (Person) c.newInstance(null);
System.out.println(p.name);
}
//反射构造函数:public Person(String name)
@Test
public void test2() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(String.class);
Person p = (Person) c.newInstance("小米");
System.out.println(p.name);
}
//反射构造函数:public Person(String name,int password)
@Test
public void test3() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getConstructor(String.class,int.class);
Person p = (Person) c.newInstance("小米",4000);
System.out.println(p.name);
}
//反射构造函数:private Person(List list)
@Test
public void test4() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Constructor c = clazz.getDeclaredConstructor(ArrayList.class);
c.setAccessible(true); //暴力反射
Person p = (Person) c.newInstance(new ArrayList());
System.out.println(p.name);
}
//创建(通过无参构造函数)对象的另外一种途径
@Test
public void test5() throws Exception{
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Person p = (Person)clazz.newInstance();
System.out.println(p.name);
}
}
public class Person {
public String name = "xiaoming";
public Person(){
System.out.println("person");
}
public Person(String name){
System.out.println(name);
}
public Person(String name,int password){
System.out.println(name+":"+password);
}
private Person(ArrayList list){
System.out.println("list");
}
}
私有的东西只能被内部访问,但是反射类可以实现。
反射类的方法:
利用Method执行方法
1.Method对象提供了如下方法,用于执行它所代表的方法:
Object invoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
2.练习:使用Method分别执行无参,有参,多参(带数组和基本数据类型),静态,私有的方法。
另:
jdk1.4和jdk1.5的invoke方法的区别:
jdk1.5:Object invoke(Object obj,Object...args)
jdk1.4:Object invoke(Object obj,Object[] args)
示例:
//反射类的方法
public class Demo2 {
//反射类的方法:public void aa1()
@Test
public void test1() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", null);
method.invoke(p, null);
}
//反射类的方法:public void aa1(String name,int password)
@Test
public void test2() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", String.class,int.class);
method.invoke(p, "xiaoming",20);
}
//反射类的方法:public Class[] aa1(String name,int[] passwprd)
@Test
public void test3() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", String.class,int[].class);
method.invoke(p, "laowang",new int[]{1,23});
}
//反射类的方法:private void aa1(InputStream in)
@Test
public void test4() throws Exception{
Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getDeclaredMethod("aa1", InputStream.class);
method.setAccessible(true);
method.invoke(p, new FileInputStream("D:\\practice1.txt"));
}
//反射类的方法:public static void aa1(int num)
@Test
public void test5() throws Exception{
// Person p =new Person(); //静态方法调用时可以不需要对象
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("aa1", int.class);
method.invoke(null, 23);
}
}
public class Person {
public String name = "xiaoming";
public Person(){
System.out.println("person");
}
public void aa1(){
System.out.println("aa1");
}
public void aa1(String name,int password){
System.out.println(name+":"+password);
}
public Class[] aa1(String name,int[] passwprd){
return new Class[]{String.class};
}
private void aa1(InputStream in){
System.out.println(in);
}
public static void aa1(int num){
System.out.println(num);
}
public static void main(String[] args) {
System.out.println("main!");
}
}
反射类的main方法:
//反射类的方法:public static void main(String[] args)
@Test
public void test6() throws Exception{
// Person p =new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Method method = clazz.getMethod("main", String[].class);
// method.invoke(null, new Object[]{new String[]{"aa","bb"}}); //方式一
method.invoke(null, (Object)new String[]{"aa","bb"}); //方式二
//jdk1.5为了兼容jdk1.4,在传入的参数是一个数组时,会把数组的元素拆成多个参数进行传递。
}
反射类的字段
//反射字段
public class Demo2 {
//反射字段: public String name = "xiaoming";
@Test
public void test1() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getField("name");
//获取字段的值
Object value = f.get(p);
//获取字段的类型
Class type = f.getType();
if(type.equals(String.class)){
String svalue = (String)value;
System.out.println(svalue);
}
//设置字段的值
f.set(p, "xxxx");
}
//反射字段: private int password;
@Test
public void test2() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getDeclaredField("password");
f.setAccessible(true);
System.out.println(f.get(p));
}
//反射字段: private static int age; 和访问私有成员变量一样
@Test
public void test3() throws Exception{
Person p = new Person();
Class clazz = Class.forName("cn.itcast.eclipse.Person");
Field f = clazz.getDeclaredField("age");
f.setAccessible(true);
System.out.println(f.get(p));
}
}
public class Person {
public String name = "xiaoming";
private int password = 12;
private static int age = 32;
public Person(){
System.out.println("person");
}
7.内省操作:introspector类
1.开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象(javabean)的属性。
2.什么是Java对象的属性和属性的读写方法:
public class Person { //javabean,这个bean有4个属性(包括getClass()属性)。
private String name; //字段
private String password;
private int age;
public String getName() { //属性
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
3.内省访问javabean属性的两种方法:
①通过Introspector类获得Bean对象的BeanInfo,然后通过BeanInfo来获得属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
②通过 PropertyDescriptor类操作Bean的属性。
//使用内省api操作bean的属性
public class Demo2 {
//得到bean的所有属性
@Test
public void test1() throws Exception{
BeanInfo info = Introspector.getBeanInfo(Person.class,Object.class); //不要class属性
PropertyDescriptor[] pds = info.getPropertyDescriptors();
for(PropertyDescriptor pd:pds){
System.out.println(pd.getName());
}
}
//操作bean的指定属性:age
@Test
public void test2() throws Exception{
Person p = new Person();
PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
//得到属性的写方法,为属性赋值
Method method = pd.getWriteMethod(); //setAge
method.invoke(p, 45);
//获得属性的值
method = pd.getReadMethod();
System.out.println(method.invoke(p, null));
}
//获取当前操作的属性的类型
@Test
public void test3() throws Exception{
PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);
System.out.println(pd.getPropertyType());
}
}
使用beanUtils操作javabean的属性
//使用beanUtils操作bean的属性
public class Demo1 {
@Test
public void test1() throws IllegalAccessException, InvocationTargetException{
Person p = new Person();
BeanUtils.setProperty(p, "name", "xcc");
System.out.println(p.getName());
}
//下面的代码有问题的,因为beaUtils框架只支持基本数据类型转换。
@Test
public void test2() throws IllegalAccessException, InvocationTargetException{
String name = "xiaoming";
String password = "123";
String age = "34";
String birthday = "1980-09-09"; //需要注册转换器
//为了让日期赋到bean的birthday属性上,我们给beanUtils注册一个日期转换器
ConvertUtils.register(new Converter(){
public Object convert(Class type, Object value) {
if(value==null){
return null;
}
if(!(value instanceof String)){
throw new ConversionException("只支持string类型的转换!");
}
String str = (String)value;
if(str.trim().equals("")){
return null;
}
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
try {
return df.parse(str);
} catch (ParseException e) {
throw new RuntimeException(e);//异常链不能断
}
}
}, Date.class);
Person p = new Person();
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "password", password);
BeanUtils.setProperty(p, "age", age); //自动将字符串转换为int。但是只支持8基本数据类型
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
System.out.println(p.getBirthday());
}
//使用beanUtils自己的转换器,但是写的不健壮。比如日期类“”传入会报错
@Test
public void test3() throws IllegalAccessException, InvocationTargetException{
String name = "xiaoming";
String password = "123";
String age = "34";
String birthday = "1980-09-09"; //需要注册转换器
//为了让日期赋到bean的birthday属性上,我们给beanUtils注册一个日期转换器
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p = new Person();
BeanUtils.setProperty(p, "name", name);
BeanUtils.setProperty(p, "password", password);
BeanUtils.setProperty(p, "age", age); //自动将字符串转换为int。但是只支持8基本数据类型
BeanUtils.setProperty(p, "birthday", birthday);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
Date date = p.getBirthday();
System.out.println(date.toLocaleString());
}
//用map集合中的值,填充bean的属性
@Test
public void test5() throws IllegalAccessException, InvocationTargetException{
Map map = new HashMap();
map.put("name", "xiaoming");
map.put("password", "123");
map.put("age", "23");
map.put("birthday", "1980-09-09");
ConvertUtils.register(new DateLocaleConverter(), Date.class);
Person p =new Person();
BeanUtils.populate(p, map);
System.out.println(p.getName());
System.out.println(p.getPassword());
System.out.println(p.getAge());
System.out.println(p.getBirthday());
}
}