`
小驴变黑马
  • 浏览: 12085 次
文章分类
社区版块
存档分类

黑马学习日记_高新技术一

阅读更多
1、Workspace与project
    切换工作空间:File---Switch Workspace---Other
    一个工作间包含多个工程,切换工作间之后,会影响里面的工程,例如快捷键什么的都要重新配置
    如果重新配了之后快捷键还没有用就要考虑下那个快捷键是不是冲突了
 
 
2、试图管理与程序调试
    可以通过Window---Show View来添加各种透视图。
    调试程序的时候可以在代码右边双击,然后选择Debugs As,就会弹出Debug的透视图,然后选择要查看
    的变量,右键选择watch即可。
 
3、设置单个工程的javac与java。
    高版本的java能否运行低版本的javac编译的程序?能
    低版本的java能否运行高版本的javac编译的程序?不能
    运行版本(java)比编译版本低(javac)的话不能运行会出现"Bad version number in .class file"问题
    总之能设置整个workspace的javac与java,也能设置单个工程的javac与java。
 
 
4、快捷键的绑定与代码模板
    新建模板步骤:选择代码---右键Surround With---Configure Template--- new...
    利用快捷键提高工作效率
    导别人的包的时候,别人编写代码的时候的jre可能和你机器上的不一样所以要把原来的给删掉,
    换成自己的JDK版本
    步骤:选中工程---右键选择Build Path---Configure Build Path---Libraries---remove掉
    然后再按这个步骤选 Add library---JRE System library。
 
 
5、静态导入:
    import语句可以导入一个类或某个包中的所有类
    import static是JDK1.5的新特性,它的意思是导入一个类中的某个静态方法或所有静态方法,就是像导
    util包或者net包一样,只不过是用到了一个类中的静态方法,这样就可以通过静态导入的方法那个类导
    进来,然后即可以直接用类中的静态方法了,其格式为下: 
    import static java.lang.Math.max;
    import static java.lang.Math.*; 
    System.out.println(Math.max(2,5));//导入之后就可以调用Math类下的静态方法了
 
6、overload和override
overload 重载 参数个数列表和类型一样只有返回值不一样 那不叫重载,那是错误。
Override重写  父类方法私有的话,子类再写一个同样的函数不叫重写,那是一个全新的方法。
 
7、可变参数:
问题:一个方法接受的参数个数不固定,例如:
System.out.println(countScore(2,3,5));
System.out.println(countScore(1,2,3,5));
可变参数的特点:
只能出现在参数列表的最后;
...位于变量类型和变量名之间,前后有无空格都可以;
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数。
部分代码:
public static void main(String[] args) 
{
System.out.println(add(1, 5, 7));
System.out.println(add(2,5));
}
//可变参数 args
public static int add(int x,int...args)
{
int sum=x;
for(int i=0;i
{
sum +=args[i];//操作可变参数时把它当数组来用
}
return sum;
}
  
 
8、增强for循环:
语法:
for ( type 变量名:集合变量名 )  { … } 
注意事项:
迭代变量必须在( )中定义!
集合变量可以是数组或实现了Iterable接口的集合类
举例: 
public static int add(int x,int ...args) 
{
int sum = x;
for(int arg:args)
{
sum += arg;
}
return sum;
}
 
 9、基本数据类型的自动拆箱与装箱
 
自动装箱:
Integer num1 = 12;
自动拆箱:
System.out.println(num1 + 12);
基本数据类型的对象缓存:
Integer num1 = 12;
Integer num2 = 12;
System.out.println(num1 == num2);true
 
Integer num3 = 129;
Integer num4 = 129;
System.out.println(num3 == num4);false
 
Integer num5 = Integer.valueOf(12);
Integer num6 = Integer.valueOf(12);
System.out.println(num5 == num6); true
注意:
★数值在-128~127之间的都放在一个池子中,下次谁在创建这样的对象就出来直接用就行了,没必要在
★去创建一个新对象那样浪费空间。就是-128~127之间的数用的太频繁,你要没用一次就创一个对象,
★那肯定会占用很多内存,于是就把这种被用的频率非常大的东西都放到一个池子里,谁用就拿走用算
★了就不用再另辟空间了。像文件夹啊  在文档里输入的字母啊
 
 
10、享元模式:
FlyWight  是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享
资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的
使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结
构,当需要使用时再将它们传递给享元。
 
自己的话(享元模式):有很多小东西都差不多,又被大量重复的使用,这样很占内存,于是就把这些差
 不多的封装成一个对象,其中它们相同属性的封装成内部状态,不一样属性的封装成外部状态,作为方
 法的参数传进来。
 
11、枚举
   11.1为什么要有枚举
问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写
成int weekday = 0;或即使使用常量方式也无法阻止意外。枚举就是要让某个类型的变量的取值只能为若
干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非
法值,普通变量的方式在开发阶段无法实现这一目标。
 
11.2用普通类如何实现枚举功能,定义一个Weekday的类来模拟枚举功能。 
1.私有的构造方法
2.每个元素分别用一个公有的静态成员变量表示
3.可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类。
 
扩展:枚举类的values,valueOf,name,toString,ordinal等方法
总结:枚举是一种特殊的类,其中的每个元素都是该类的一个实例对象,
例如可以调用WeekDay.SUN.getClass().getName和WeekDay.class.getName()
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
 
 总结枚举的特点:
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
 枚举是一个特殊的类,每个元素都是这个枚举类的实例对象,它里面可以有也可以定义构造方法、成员变
 量、普通方法和抽象方法。但是枚举类里面的构造函数必须是私有的,因为你不私有的话别人就能创建对
 象,那就违背了用枚举的目的了,然后枚举类里面的元素要放在最前面,并且后面加分号。可以通过内部
 类的方法实现枚举类里面的抽象函数。然后当枚举类中就一个元素时,它就是单例。
 
 用枚举写单例有什么好处呢?
首先私有化的构造函数不用写了吧,因为美剧默认的构造函数就是私有的, 然后自己new一个对象出来这一步也不用了吧,因为枚举里面的元素就是一个枚举类的实例对象。
 
 
12、反射
反射的基石àClass类
我们运行程序的时候,通常会产生一些与xxx.java文件对应的xxx.class文件,写的代码多了,.class文件就
多了,因为它也是一种事物的类型啊,有共性的东西存在,比如是.class文件它就有名字吧,它里面就有方法
吧,它里面就有成员变量吧等等,因为它也是一种有共性的事物,所以java把.class文件也封装成了一个对象,
就是Class,每一个.class文件都是他的一个实例,.class文件也叫字节码文件。
 
既然把所有的字节码文件都是Class类的对象了,那么Class类就和其他类差不多,就是能通过Class获得它的
对象吧?就像普通类你要new对象一样,然后通过Class类能获得里面的方法和成员变量吧?
 
Class类代表Java类,它的各个实例对象又分别对应什么呢?
对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码,等等。
一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字
节码是不同的,所以它们在内存中的内容是不同的,这一个个的空间可分别用一个个的对象来表示,这些对
象显然具有相同的类型。
黑马程序员——高新技术1 - hm_yong_jie - hm_yong_jie的博客
 
如何得到各个字节码对应的实例对象( Class类型)
具体类名.class,例如,System.class
具体对象.getClass(),例如,new Date().getClass()
Class.forName("类名"),例如,Class.forName("java.util.Date");
 
Class.forName的作用:
1、如果JVM里没有该字节码。则类加载器把该类字节码加载到内存,把加载进
来的字节码缓存到缓存里。同时返回字节码。
 2、如果JVM有该字节码。则直接从缓存里拿字节码并返回。
 
9个预定义的Class对象 八个基本数据类型和void
Class.isPrimitive()// 查看是否是基本数据类型的字节码
基本数据对象类型可以写成 如:Integer.TYPE 获取字节码
Integer.TYPE//表示基本类型 int 的 Class 实例。 
 
数组类型的Class实例对象
Class.isArray()//判定此 Class 对象是否表示一个数组类。 
总之,只要是在源程序中出现的类型,都有各自的Class实例对象,例如,int[],void…
 
什么是反射呢?
我们知道,一个字节码文件中肯定会有很多方法,成员变量什么的,那么Class既然是所有字节码的总称了,
那么它里面肯定会有用来获取字节码里的变量,函数,构造函数等一些列的方法了?而获取来的这些信息就
用Field、Method、Contructor、Package等等这些Class的实例对象来表示。 
 
 
反射获取构造函数 Constructor类
步骤:先获取字节码文件,然后通过 getConstructors()方法获取里面的构造函数,写的时候要往里传
入参数的类型来确定你要的是那个构造函数。
 
1,得到某个类所有的构造方法:
Constructor[] constructor = Class.forName("java.lang.String").getConstructors();
2,得到某一个构造方法:
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
3,创建实例对象:
通常方式:String str = new String(new StringBuffer("abc"));
反射方式:String str = (String)constuctor.newInstance(new StringBuffer("abc"));
 
反射获取成员变量   Field类
通过反射获取变量值,要先获取这个字节码中有哪些变量,然后再获取是哪个对象里的变量的值。因为
一个类可以new很多对象啊,每个对象里的变量值可能会不一样,所以获取到变量名以后要指定是哪个对
象的变量
 
部分代码:
class ReflectPoint
{
private int x;
public int y;
 
ReflectPoint()
{
this x = x;
this y = y;
}
}
//创建一个ReflectPoint对象,并初始化x y的值
ReflectPoint rf1 = new ReflectPoint(3,5);
//先利用反射求出字节码文件中的某个成员变量(返回的是某个成员变量而不是具体值)
Field fieldY = rf1.getClass().getField("y");
//因为一个类可以有很多对象,每个对象的成员变量的值又不一定相同,所以返回
//了某个成员变量后,还要通过get方法获取是哪个对象的成员变量的值
System.out.println(fieldY.get(rf1));
System.out.println(fieldX.get(rf1));
Field fieldX = rf1.getClass().getDeclaredField("x");//获取类中的私有变量
fieldX.setAccessible(true);//获取到私有变量并把其设置成可以访问
System.out.println(fieldX.get(rf1));
 
 
反射作用,例如扫描你配置文件里的配置给你替换掉。
练习:将任意一个对象中的所有String类型的成员变量所对应的字符串内容中的"b"改成"a"。
反射作用,例如扫描你配置文件里的配置给你替换掉。
部分代码:
private static void changeStringValue(Object obj) throws Exception
{
//得到的是字节码文件中所有的变量,返回的是一个数组,数组里面是所有变量的名字
Field[] fields = obj.getClass().getFields();
for(Field field:fields)//循环遍历存有所有的变量的数组
{
//变量字段也有字节的类型然后与String的类型相比较
if(field.getType()==String.class)//找到是名为String类型的变量
{
String oldString = (String)field.get(obj);
String newString = oldString.replace("b", "a");
//转换之后,要重新设置一下,上面只是get没有set
field.set(obj, newString);
}
}
}
 
反射获取函数  Method类
步骤:还是先获取字节码文件,然后通过Class的实例对象Method存储获取来的字节码中的方法,通过
getMethod()来获取方法的时候,要往里面传两个参数,一个是方法名一个是方法的参数类型。找到需
要的方法时再通过invoke传入是哪个对象调用的此方法和具体的参数值。又因为一个函数的参数有可能
是多个所以往里传的参数类型是可变参数。
 
String str1="abc";
通常方式:System.out.println(str.charAt(1));
反射方式:
//利用反射获取字节码文件中的某个特定的方法getMethod(方法名, 参数类型.class);
Method methodcharAt = String.class.getMethod("charAt", int.class);
//invoke(obj, args)意思就是那个对象调用这个方法并把参数春进来
System.out.println(methodcharAt.invoke(str1,1));
//因为invoke方法前面是哪个对象在调用反射出来的那个方法,如果对象为空的话,那说
//明不能被对象调用,那这个方法就是静态方法了
System.out.println(methodcharAt.invoke(null,1));
 
 
jdk1.4和jdk1.5的invoke方法的区别:
Jdk1.5:public Object invoke(Object obj,Object... args)
Jdk1.4:public Object invoke(Object obj,Object[] args),即按jdk1.4的语法,需要将一个数组作
为参数传递给invoke方法时,数组中的每个元素分别对应被调用方法中的一个参数,所以,调用charAt
方法的代码也可以用Jdk1.4改写为 charAt.invoke(“str”, new Object[]{1})形式。
 
用反射方式执行某个类中的main方法
目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的main方法。用普通方式调完后,大
家要明白为什么要用反射方式去调啊?
因为你在运行时可能不知道要运行的那个主函数是属于哪个类的?比如说别人把类名当参数传给你了,
说这个数组里的第一个元素就是那个类的名字,这样的话你怎么办?你压根就不知道那个类的名字是
什么啊?这就用到了反射了。
就是说我要调用你那个类的main方法,我代码写完了,你还没说让我调那个,但是我照样能实现。
就像这样:
String startingClassName = args[0];//从数组里取出那个元素的值用一个变量存储
Method mainMethod = //然后用Class.forName(startingClassName)获取字节码文件
Class.forName(startingClassName).getMethod("main", String[].class);
mainMethod.invoke(null,(Object) new String[]{"111","222","333"});
 
 
反射的基本步骤:
1.通过那三种方式先获取字节码对象
2.实例化字节码对象,再获取字节码中的构造函数,方法以及变量
3.通过传参数等方法确定你要用的是哪个方法或者变量。
 
 
用反射方式执行某个类中的main方法
当你在写程序的时候,需要用到另个类的main方法,而另个类是别人写的,你不知道类名,这个时候就
不能用 "类名.main(String[] args)"这种方法来完成调用了,而需要用反射机制。用反射方法完成对
某个类main方法的方法,写完之后把类名穿过来就行了。
 
 可问题是:
启动Java程序的main方法的参数是一个字符串数组,即public static void main(String[] args),通
过反射方式来调用这个main方法时,如何为invoke方法传递参数呢?按jdk1.5的语法,整个数组是一个
参数,而按jdk1.4的语法,数组中的每个元素对应一个参数,当把一个字符串数组作为参数传递给invoke
方法时,javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按jdk1.4的语法进
行处理,即把数组打散成为若干个单独的参数。所以,在给main方法传递参数时,不能使用代码
mainMethod.invoke(null,new String[]{“xxx”}),javac只把它当作jdk1.4的语法进行理解,而不把它
当作jdk1.5的语法解释,因此会出现参数类型不对的问题。
 
总的来说:因为任意一个类中的main方法中都是接受一个String参数数组,为JDK1.4没有可变参数,传多
个参数的话都用数组,就是数组中每个元素都是一个参数,所以在JDK1.4中这样的话
mainMethod.invoke(null,new String[]{"111","222","333"});javc会以为是你传了三个参数进来。所以
当你传入的参数是个数组时就要注意了,要把这个数组套在一个数组中,这样在1.4看来里面的那个数组就
是参数了。
 
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"}); ,编译器会作特殊处理,编译时不把参数当
作数组看待,也就不会数组打散成若干个参数了
 
 
 
 
数组的反射:
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
int [] a1 = new int[]{1,2,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());true
System.out.println(a1.getClass() == a4.getClass());false
System.out.println(a1.getClass() == a3.getClass());false
Object aObj1 = a1;
Object aObj2 = a4;
Object[] aObj4 = a3;
Object[] aObj5 = a4;
 
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;
非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
 
Arrays.asList()方法处理int[]和String[]时的差异。
处理int[]时打印的是数组名和哈希值,处理S特ring[]时打印出来的是数组里面的元素。
就是集合里面装的是对象,那int[]数组转换为集合后不可能数组里面的元素就是集合里面的元素,
因为数组里面的是int型值不是对象,而String数组里面的字符串本来就是一个对象,所以转换为
集合后可以打印出来。
 
Array工具类用于完成对数组的反射操作。
思考题:怎么得到数组中的元素类型?
private static void printObject(Object obj)
{
Class clazz = obj.getClass();//获取字节码文件
if(clazz.isArray())//判断字节码是不是数组
{
int len = Array.getLength(obj);//是的话获取数组长短
for(int i=0;i
{
System.out.println(Array.get(obj, i));
}
}
else
{
System.out.println(obj);
}
}
  
 
HashCode的作用?
HashSet集合是不允许里面的元素有相同的
哈希算法就是把集合分成了若干个区域,每一个要存进来的对象可以算出一个值,根据算出来的值,把
它放到相应的区域里面去。当某个对象要存进来时,先算出它的HashCode值,根据它的哈希值判断,把
对象放到它所对应的区域,这样对于查找某个对象直接算出他的HashCode值,这样不用挨个去排查,直
接找出对象所在的区域即可,提高了效率。HashSet就是采用了哈希算法的集合,所以在HashSet中判断
是否是同一个元素不光要判断equals还要判断hashCode。
 
注意:当一个对象被存储进HashSet集合以后,就不要再改动这个对象中参与哈希值运算的变量了,否则
会造成内存泄露。因为你存进去之后,改变那个参与哈希值运算的变量的话,那这个对象的哈希值也就
跟着变了,你再按这个哈希值删除对象的话会删不掉,因为你存到这个区域了,哈希值一变你删除的就
是另个区域的值了,而存进来的那个对象还依然在原位置存放着呢。
 
内存泄露:
所谓内存泄露就是有一个对象我不再用了,但它还一直占用着空间没有被释放。比如当把一个对象存进了
hashset集合以后,又改变了这个对象中参与计算哈希值的字段了,
 
反射的作用à实现框架功能
 
框架和工具类不同,框架是调用者,工具类是被调用者
 
框架要解决的核心问题
    我在写框架时,你这个用户可能还在上小学,还不会写程序呢?我写的框架程序怎样能调用到你
    以后写的类呢?因为在写才程序时无法知道要被调用的类名,所以,在程序中无法直接new某个
    类的实例对象了,而要用反射方式来做。我们可以用一个类来写配置文件,写的时候通过反射配
    置文件的获得相应的类名,然后用户拿到框架的时候只需要把类名写到配置文件中就可以使用整
    个框架了。
 
1,配置文件放在哪里,在实际开发中没有用相对路径这样写的配置文件的,如:
     InputStream isp = new FileInputStream("config.properties");
     最好用getRealPath();方法  不管用户安装到那个目录下都能获取到它所在的位置。一定要记住用完
     整的路径,但完整的路径不是硬编码,而是运算出来的。 
2. 每一个.class文件,我们在用它的时候都要把他加载到内存来,用到类加载器。
ReflectTest2.class.getClassLoader().getResourceAsStream("配置文件");
这个方法的意思是在classpath指定的那些目录下逐一的去查找要加载的文件。
这种方式只能读。无论是相对路径还是绝对路径,内部调用的都是getClassLoader();
eclipse会源程序目录下的所有的.java文件自动编译成、class文件,保存的时候就编译了,并且放到
classpath指定的目录下去,而把非.java的文件原封不动的搬到那个目录。
---------------------- android开发java培训、期待与您交流! ----------------------
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics