您的位置:首页 > 编程语言 > Java开发

Java基础---基础加强---增强for循环、自动拆装箱及享元、枚举的作用、实现带有构造方法、透彻分析反射的基础_Class类、成员变量的反射、数组参数的成员方法进行反射、数组的反射应用

2014-04-03 23:18 1511 查看
在perference 加content Assist 可以设置快捷键



透视图与视图

透视图:Debug和java主窗口

视图:每一个小窗口就是视图

高版本的java可运行低版本的java版本

常见的错误:classversionError

一般都是文件编译与系统默认的编译器版本不同导致的。

在配置文件里把java compiler变了,整个工作间都会跟着改变

如何自己配置模板:

在preferences中有一个Editor。下面有一个Template,里面可以设置

提示:

如果在导入工程的时候,发现在jdk版本不一样,我们可以在Build Path下找到java Build path 有一个Libraries删除原来的jRE库,重新导入新的jRE,很多的jar文件在一起就称之为库,jre相当于打包的过程

静态方法的导入java.lang.*;

jdk1.5的新特性

1.可变参数

一个方法接受的参数的个数不固定,例如:System.out.println(add(1,2,5);

System.out.println(add(1,2,3,5);

可变参数的特点:

只能出现在参数列表的最后。

位于变量类型和变量名之间。前后有无空格都可以。

调用可变参数的方法时,编译器为该可变参数隐含创建一个数组。在方法中以数组的形式访识破可变参数

overload override:

深入理解。



public class StaticImport {

public static void main(String []args){
//int x=1;
//x++;
System.out.println(add(2,3));
System.out.println(add(2,3,4));
//System.out.println(Math.max(3,6));
}

public static int add(int x,int ...args){
int sum=x;
for(int i=0;i<args.length;i++){
sum+=args[i];
}
return sum;
}

}


增强for循环

语法(类型 变量名:集合变量名)

注意事项:

跌代变量必须在()中定义。

集合变量可以是数组或实现了Iterable接口的集合类。

2.基本数据类型的自动拆箱与装箱及享元设计模式。

自动装箱

Integer num1=12;

自动拆箱

System.out.println(num1+12);

i{char,x,y},为了共用。里面的参数

享元设计模式:

如果很多很小的东西,它们具有相同的属性,我们就可以把它变成一个相同的对象。这些称之为内部状态。那些不同的属性作为方法的参数传入,称之为外部状态

3.枚举

枚举就是要让某个类型的变量取值只能为若干个固定值中的一个,否则,编译器就会报错,枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能 。

私有的构造方法。

每个元素分别用一个公有的静态成员表量表示

可以用若干个公有方法或抽象方法,例如,要提供nextday方法必须是抽像的


public abstract class WeekDay1 {

private WeekDay1(){

}
public final static WeekDay1 Sun=new WeekDay1(){

@Override
public WeekDay1 nextDay() {
// TODO Auto-generated method stub
return Mon;
}

};
public final static WeekDay1 Mon=new WeekDay1(){

@Override
public WeekDay1 nextDay() {
// TODO Auto-generated method stub
return Sun;
}

};
public abstract WeekDay1 nextDay();

//	public WeekDay nextDay(){
//		if(this==Sun){
//			return Mon;
//		}else{
//			return Sun;
//		}
//	}
public String toString(){
return this==Sun?"Sun":"Mon";
}

}
为了更多的理解枚举,采用抽象方法定义next.day就将大量的if.else语句转移成了一个个独立的类。

如果想在一个类中完成各个枚举和测试调用类,那么就可以将枚举类定义成调用类的内部类。

内部类可以有4个访问修饰符。

一般的成员方法就是2个。public private,内部类与成员方法是平级的


package day01;

import java.sql.Date;

public class EnumTest {

public static void main(String[] args) {

WeekDay1 weekDay=WeekDay1.Mon;//赋值给引用变量
System.out.println(weekDay.nextDay());
WeekDay weekDay2=WeekDay.Fri;
System.out.println(weekDay2);
System.out.println(weekDay2.name());
System.out.println(weekDay2.ordinal());
//把静态的串变成枚举方法
System.out.println(weekDay2.valueOf("Sun"));

new Date(300){
//调用父类的构造方法,调用有参的构造
};

}

public enum WeekDay{
Sun,Mon,Tue,Fri;//相当于里面的类。如果我们写成Sun(1),可会调用第二个方法
//定义带有参数的构造方法
private WeekDay(){
System.out.println("first");
}
private WeekDay(int day ){
System.out.println("second");
}
}

//带有抽象方法的枚举类
public enum TrafficLamp{
Red(30){//red是一个元素,它是由trafficLamp子类来实现的
public TrafficLamp nextLamp(){
return Green;
}

},
Green(45){
public TrafficLamp nextLamp(){
return Yellow;
}
},
Yellow(5){
public TrafficLamp nextLamp(){
return Green;
}
};
public abstract TrafficLamp nextLamp();

private int time;
private TrafficLamp(int time){
this.time=time;
}

}
}


抽象类的返回值还是自己

枚举就相当于一个类,其中也可以定义构造方法,成员变量,普通方法和抽象方法。

枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后面要有分号与其他成员分隔,把枚举中的成员或变是等放在枚举元素的前面,编译器报告错误

带枚造方法的枚举

1.构造方法必须定义成私有的

2.如果有多个构造方法,该如何选择哪个构造方法?

3.枚举元素MON和MON()的效果一样,都是调用默认的构造方法。

带方法的枚举

1.定义枚举TrafficLamp

2.实现普通next的方法

3.实现抽象的next方法,每个元素分别是由枚举的子类来生成的实例对象,这些子类采用类似的内部类的方式进行定义

4.增加上不表示时间的构造方法

枚举只有一个成员时,就可以作为一种单例的实现方式。

反射

Person p1=new Person();

Class代表内存里央的字节码,不能实例化对象。

p1.getClass()也是代表person那个字节码

Class cls1=Data.class//字节码1;Data.class代表Data的那个字节码

Class cls2=Person class//字节码2;

Person class代表Person的那个字节码

每一份字节码就是一份Class的实例对象

还有一种是Class.forName("java.lang.String"),在写源程序的时候,可以把括号里面的变成变量,字符串变量,程序启动,从配置文件里装载进来。类的名字,在写的时候可以不知道,在运行的时候,临时送进来

这个forName的作用是:

1.返回刚刚加载进来的字节码

返回的方式有两种,第一种是说这份字节码曾经被加载过,已经在JVM里面了,直接返回。第二种是JVM还没有这个字节码,则用类加载器去加载,把加载进来的字节码缓存在JVM中,以后要得到这份字节码,就不用加载了

有9个预定义的class对象,8个基本类型加一个void

记得加了void,如Class cls1=void.class;

反射比较占用时间,它是先把构造方法存起来,如果有人要用了,再把它拿出来。这过程中就消耗了时间。

如何你在一个配置文件里,配置了好多东西,我们可以通过反射来修改。这个功能相当有用

面向对象就是把变量搞成私有的,如果谁要调用这个对象,那么方法就应该在谁身上



package day01;

import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays;

public class ReflectTest {

public static void main(String[] args)throws Exception {

String str1="abc";
Class cls1=str1.getClass();
Class cls2=String.class;
Class cls3=Class.forName("java.lang.String");
System.out.println(cls1==cls2);
System.out.println(cls2==cls3);
//JVM中只存在一份字节码。供不同的对象调用
//String不是基本类型的字节码,它是一个类
System.out.println(cls1.isPrimitive());//isprim表示一个原始类型
System.out.println(int.class.isPrimitive());
System.out.println(int.class==Integer.class);
System.out.println(int.class==Integer.TYPE);//表示包装类型的那个基本类型的字节码,所以为True
System.out.println(int[].class.isPrimitive());//返回false,因为数组也是一个实例对象,用的方法是Class.isArray();

//new String(new StringBuffer("abc"));
Constructor constructor1=String.class.getConstructor(StringBuffer.class);//第一个StringBuffered表示选择哪个构造方法
String str2=(String)constructor1.newInstance(new StringBuffer("abc"));//每调用一次相当于New了一次对象。第二个StringBuffered表示用这个StringBuffered传哪个对象进去。
//在编译的时候,只知道constructor1是构造方法,而不知道是哪个类下的构造方法,编译器只看变量的类型,而不看执行
System.out.println(str2.charAt(2));
//得到方法的时候需要类型,在调用方法的时候,还是要类型

ReflectPoint pt1=new ReflectPoint(3, 5);
Field fieldY=pt1.getClass().getDeclaredField("y");
//FieldY的值是多少?5,错,没有对应到对象身上,Field
//不代表一个具体的值,只代表一个变量,而且是字节码里面的一个变量
//它是指向哪个类身上的值
fieldY.setAccessible(true);//这里用到的是暴力反射。
System.out.println(fieldY.get(pt1));

changeStringValue(pt1);
System.out.println(pt1);

//直接调用,str1.charAt(1);
Method methodCharAt=String.class.getMethod("charAt", int.class);
//得到字节码里面的方法,再用方法去作用某个对象
System.out.println(methodCharAt.invoke(str1, 2));//args表示传几个参数。str1这个字符串身上调用charAt
//invoke是方法对象身上的方法

System.out.println(methodCharAt.invoke(str1, new Object[]{2}));//2表示一个object
//这是jdk1.4里面的方法

String startingClassName=args[0];
Method mainMethod=Class.forName(startingClassName).getMethod("main", String[].class);
//mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});//把三个参数包到一起传送进去
mainMethod.invoke(null,(Object)new String[]{"111","222","333"});
//每个数组的父类都是object

int [] a1=new int[3];
int [] a2=new int[4];
int [][] a3=new int [2][3];
String [] a4=new String []{"a","b","c"};
System.out.println(a1.getClass()==a2.getClass());
//System.out.println(a1.getClass()==a4.getClass());
//System.out.println(a1.getClass()==a3.getClass());

Object aObj1=a1;
Object aObj2=a4;
//Object[] aObj3=a1;//int不是object,基本类型不是Object,基本类型的一维数组不能转成object数组
Object[] aObj4=a3;//二维是object
Object[] aObj5=a4;//String是object

System.out.println(Arrays.asList(a1));
System.out.println(Arrays.asList(a4));//只接受String类型,因为它是object数组

printObject(a4);
printObject("xyz");

}

private static void printObject(Object obj){
Class clazz=obj.getClass();
if(clazz.isArray()){
int len=Array.getLength(obj);
for(int i=0;i<len;i++){
System.out.println(Array.get(obj, i));
}
}else{
System.out.println(obj);
}
}

private static void changeStringValue(Object obj) throws Exception{
Field [] fields=obj.getClass().getFields();//得到所有的字段
for(Field field:fields){
//if(field.getType().equals(String.class)){
//对字节码的比较应该拿==相比
if(field.getType()==(String.class)){//这里应该用==,因为是同一份字节码
String oldValue=(String) field.get(obj);
String newValue=oldValue.replace('b', 'a');
field.set(obj, newValue);

}
//这个field代表字段

}
}

}

class TestArguments {
public static void main(String[] args) {
for(String arg:args){
System.out.println(arg);
}
}
}



ReflectPoint.java

package day01;

public class ReflectPoint {

private int x;

public String str1="ball";
public String str2="basketball";
public String str3="haha";

public int y;

public ReflectPoint(int x, int y) {
super();
this.x = x;
this.y = y;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + x;
result = prime * result + y;
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ReflectPoint other = (ReflectPoint) obj;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}

@Override
public String toString(){
return str1+":"+str2+":"+str3;
}
}


例子:

通过反射来调来main方法

数组的反射

int [] a=new int[3];

object[] a=new object[]("a",1)

a[0].getClass().getName();//只能得到它的元素的类型,不能得到a是什么类型

反射的综合应用。

ArrayList 是有顺序的数据。每放一次就引用一个变量。不是排序,而是位置顺序。

HashSet

先判断里面有没有这个对象,如果发现有的话,就不放。如果实在要放,就把原来的数据给删除掉。然后插入进去。

HashCode方法与HashSet类

如果想查找一个集合是否包含某个对象,大概的程序怎样写呢?你通常是逐一取出每个元素与要查找的对象的进行比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则,则返回否定的信息。如果一个集合中有很多元素,譬如有10000个元素,并且没有包含要查找的对象时,则意味着你的程序需要从该 集合中取出一个元素进行逐一比较才能得到结论。有人发明了哈希算法来提高从集合中查找元素的效率,这种方式将集合分成若干个区存储。每个对象可以计算出一个哈希码。可以将哈希码分组。每组分别对应某个存诸区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域

hashcode的作用:

对象要有作用,必须在hash算法类的集合中,hashcode的值才有价值。两个相同的对象被存到了不同的Hashset内存里,当要再找这个对象时,只能在本区域里进行查找。如果对象不存到hashset集合里,那么也没有必要用到hashcode方法。

提示:

通常来说,一个类的两个实例对象用equals()方法比较的结果相等时,它们的哈希码也必须相等,但反之则不成立,即equals方法比较结果不相等的对象可以有相同的哈希码。

或者说哈希码相同的两个对象的equals方法比较的结果可以不等,例如,字符串“BB” 和“Aa"的equals方法比较结果肯定不相等,但它们的hashcode方法返回值相等。


2.当一个对象被存储进HashSet集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段,否则,对象修改后哈希值最初存储进HashSet集合中时的哈希值就不同了,在这种情况下,即使在Container方法使用该对象的当前引用作为的参数去HashSet集合中检索对象,也将返回找不到对象的结果,这也会导致无法从Hashset集合中单独删除当前对象,从而造成内存泄露。

package day01;

import java.io.FileInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Properties;

public class ReflectTest2 {

public static void main(String[] args) throws Exception{

InputStream ips=new FileInputStream("config.properties");//这里用到的是相对路径
//现在的内容是ArrayList.所以结果是4,
//如果把properties中的内容改为Hashcode,结果就变为2
//这里就用到了反射技术开发框架的原理
Properties props=new Properties();
props.load(ips);
ips.close();//告诉操作系统把这个流关闭

String className=props.getProperty("className");
Collection collections=(Collection) Class.forName(className).newInstance();
//调用不带参数的构造方法
//Collection collections=new HashSet();
ReflectPoint pt1=new ReflectPoint (3,3);
ReflectPoint pt2=new ReflectPoint (5,5);
ReflectPoint pt3=new ReflectPoint (3,3);
collections.add(pt1);
collections.add(pt2);
collections.add(pt3);
collections.add(pt1);

//pt1.y=7;//这个集合与hashcode没有关系
//collections.remove(pt1);
System.out.println(collections.size());
}
}


反射的作用--->实现框架功能


newStance(),调用不参数的构造方法
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: