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


在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(),调用不参数的构造方法


你可能感兴趣的:(成员变量的反射,枚举的作用,增加for循环,实现带有构造方法)