基础知识非常重要,基础知识的深入程度决定了你能力
学习能力很重要,在未来的工作生活中,这是最重要的能力
每个知识点,会看会学会写会教人,才能达到熟练掌握的程度
1)IDE:ItegrityDevelopment Enviroment,集成开发环境
2)JavaEE:javaEnterprise Edition:java企业版开发工具。
3)JMS:Java MessageService,Java消息服务,是一个Java平台中关于面向消息中间件的API,用于在两个应用程序间,或分布式系统中,发送消息,进行异步通信。
4)JMX:Java ManagementExtensions,Java管理扩展;是一个为应用程序、设备、系统植入管理功能的框架。
5)JNDI:Java Nameingand Directory Interface:Java命名和目录接口。
6)JDBC:Java DataBase Connectivity:Java数据库连接。
3、Myeclipse和eclipse的区别:
1)Myeclipse:是elipse的插件,用于开发javaEE的平台,为其打补丁,扩展其功能,可以开发JavaEE程序即web项目,但是现在Myeclipse也集成了eclipse的功能,可直接使用Myeclipse。
2)eclipse:是开发java的一款专业的IDE(集成开发环境),以前需要Myeclipse才能开发JavaEE程序,现在的eclipse的版本也可以不用再安装Myeclipse插件,直接可以开发JavaEE项目。
顶级的目录就是工程, 打开工程后 里面会有一个以包名分级展现的java源文件 以及这个工程要用到的第三方类
window preferences(首选项)就是你的喜好 java compiler 编译器(按哪个版本进行编译)
这里有两个设置 做开发时有两个阶段,一个是编译时阶段,一个是运行时阶段 要保证编译时和运行时用的版本一样,否则会报错
配置快捷键 General->keys,设置alt+/键进行内容提示时,要注意解除alt+/键原来的绑定关系,直接输入alt+/就可以找到它的绑定关系,删除绑定关系时也可以使用remove binding这个按钮
一个工作间包含多个工程,一个工作间的设置,影响这个工作简单的所有工程
新建工作间:
file switch workspace other 进行工作间切换
当当前状态下没有你要找的工作间,这时就可以重新建立一个新的工作间,会在硬盘上自动创建工作间
因为它在创建工作间时,要把原来的工作间关掉,要用eclipse 重新打开新的工作间,加载这个工作间特有的配置信息,所以花的时间要长一点。
这时就可以在工作间创建工程了。 file new project 在弹出的对话框中选择 java project(普通的java工程)
refactor 重构包名 右键点击包名
工程的名字要尽量用英语
要养成良好的编程习惯,都要有包名,前面是公司的网址,域名,倒过来写,去哪个公司面试就写哪个公司
工程 包名 类名 变量名 等等 最好都用英语 逼着自己将英语学好
面试时主考官不会去看你的代码,你的算法,人家就看你的整体效果
怎么调试一个变量
在编辑区域内单击右键 选中 debug as 所谓不同的透视图就是指有不同的若干个小窗口的集合
在不同的应用情景下 要调用一些不同的小窗口 只要切换到不同的窗口即可
若某个窗口没有找到 就 window show view去进行查找
对这些视图要会分类会揣测
设置单个工程的javac与java。
高版本的java能否运行低版本的javac编译的程序? 能
低版本的java能否运行高版本的javac编译的程序? 不能
工作台和工程 类似于java中的继承与覆盖的关系(工作台上面的工程,所用的配置都是工作台的配置,但是它也是可以单独进行配置,覆盖掉工作台原有的配置)
选择java模板代码之一
右键->Surround With->选择即可
编辑模板代码
Perferences-->Java-->Editor-->Templates-->New
try
{
${line_selection}//这里的选项是在InsertVariable选择的
}
finally
{
${cursor}//光标
}
首先将希望要导入的工程放到工作台下面来,这个工作台下面就多了一个工程,但是eclipse就没有发现你放进来的那个工程 这时就需要将工程进行导入操作
file import general existing projects into workspace
这个存在飞工程要选择其存在的根目录,就导入了,这时要注意你导入工程jdk的安装目录 jar包是否一样 若不一样 则
右键点击工程 build path configure build path 在第三个 libraries中将jdk这个库删除掉 然后增加你自己的库 在这里进行增加时 要选择 add library 不要选add jar 因为这个是增加一个单独的jar包,对于你工程内部的jar包(你将某个jar包拷贝到你的工程中来了,就选add jar)
import语句可以导入一个类或某个包中的所有类
import static语句导入一个类中的某个静态方法或所有静态方法
语法举例:
import static java.lang.Math.sin;
import static java.lang.Math .*;
import static java.lang.Math.max;
以前是导入一个类 现在 导入的是类下的一个方法,这时调用该方法时就可以省略类名了
可变参数的特点:
只能出现在参数列表的最后; (int x,int...args) 这样可以
位于变量类型和变量名之间,前后无空格都可以; (int x,int...args,int y) 这样不对
调用可变参数的方法时,编译器为该可变参数隐含创建一个数组,在方法体中以数组的形式访问可变参数
面试题:
overload和override的区别 即,重载与重写
overload 两个参数的个数 列表 类型完全一样 只有返回值不一样 不行 还要说出为什么不行
override 如果父类的方法是私有的,子类写一个方法跟它一样 是不是叫重写 是不是叫覆盖 不对 这等于是一个全新的方法
不仅仅说两个的区别 要有一些很深入的东西
语法:
for ( type 变量名:集合变量名 ) { … }
用变量逐一去取集合中的元素,取出来后就执行循环体
注意事项:
迭代变量必须在( )中定义!
集合变量可以是数组或实现了Iterable接口的集合类
举例:
基本数据类型的自动拆箱与装箱
自动装箱:
Integer num1 = 12; 自动将一个基本数据 封装成一个Integer对象, 再赋值给引用变量
自动拆箱:
System.out.println(num1 + 12); 将num1转换成基本数据类型再进行加法 这个过程叫做拆箱
Integer i1 = 13; 变成137 又不是同一个了 因为大的数据使用频率比较低 就没有用享元模式
Integer i2 = 13;
System.out.println(i1 == i2);
基本数据类型的对象缓存:
Integer num1 = 12;
Integer num2 = 12;
System.out.println(num1 == num2);
Integer num3 = 129;
Integer num4 = 129;
System.out.println(num3 == num4); 数值超过后就不相同了
他们装出来的Integer对象是否是同一个
若在-128~127之间的数字 一旦将其封装成integer对象,就会将其缓存起来,当下次又要将一个整数封装成integer对象时,先看缓存池里有没有 有的话直接拿,这样就节省了内存空间,因为这些比较小的数使用频率会很高,反复的出现,一出现就把它装成一个对象,到最后对象会越来越多;这个对象本来就是不怎么改变的,对象又很小,大家又都是用它,又不去改变它的数据,没必要每一个数字对应一个对象
这是一种设计模式,叫做享元模式flyweight
当这个数据对象很小,又有多个地方要整出很多个这样的对象来,但搞出的对象在用的过程中都是一模一样的,那就搞一个就可以了
Integer num5 = Integer.valueOf(12);
Integer num6 = Integer.valueOf(12);
System.out.println(num5 == num6);
Integer.valueOf(12);这个方法可以将一个整数变成integer 这个不是自动装箱,而是我手动调用静态方法,把一个基本类型的整数变成一个包装类型的对象
enum
从1.5开始,将从C语言去掉的东西又给加上了
枚举的权重比较大
为什么要有枚举
问题:要定义星期几或性别的变量,该怎么定义?假设用1-7分别表示星期一到星期日,但有人可能会写成int weekday = 0;或即使使用常量方式也无法阻止意外。
枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译就会报错,枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这个目标
枚举的高级应用
枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。
枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。
带构造方法的枚举
构造方法必须定义成私有的
如果有多个构造方法,该如何选择哪个构造方法?
枚举元素MON和MON()的效果一样,都是调用默认的构造方法。
带方法的枚举
定义枚举TrafficLamp
实现普通的next方法
实现抽象的next方法:每个元素分别是由枚举类的子类来生成的实例对象,这些子类采用类似内部类的方式 进行定义。
增加上表示时间的构造方法
枚举只有一个成员时,就可以作为一种单例的实现方式
定义一个新的类型,按这个类型定义的变量,指向的值只能是固定变量的值
每一个枚举元素都是一个对象
可以有若干公有方法或抽象方法。采用抽象方法定义nextDay就将大量的if.else语句转移成了一个个独立的类
只要用到了枚举类,里边的静态变量都会被初始化, 执行 就会调用构造方法 所以会执行结果 first
只要用到了类 里边的静态代码都会执行,
在枚举元素后面跟上括号,就表示创建这个元素指向实例对象的时候使用哪个构造方法
每个元素是这个类的实例对象,这个实例对象不能直接拿到这个类去new,只能拿这个类的子类去new,new有个对象,并且对象的名字叫RED。
先定义三个元素 每个元素后面跟着一堆大括号 然后在大括号中写子类的实现代码
枚举 顺带复习内部类 运用到内部类的很多知识
提高一种编程思想
返回方法类型 可以是自己本身的类型
类里边可以定义静态常量 常量指向的结果就是自己这个类型的实例对象
枚举只有一个成员时,就可以作为一种单例的实现方式
如果要写单例,可以定义一个枚举,并且这个枚举里只有一个元素,因为枚举就是一个特殊的类,
为什么要用枚举来写单例
构造方法不用自己写,外部类是私有的,不带参数的,元素是自然的就new出来
(平时使用的是class 创建的类,这里所说的Class是一个大写的类.)
Java类用于描述一类事物共性,该类事物有什么属性,没有什么属性,至于这个属性的值是什么,则是由这个类的实例对象来确定的.
不同的实例对象有不同的属性值.Java程序中的各个Java类,它们是否属于同一类事物,是不是可以用一个类来描述这类事物呢?
这个类的名字就是:Class,要注意与小写class关键字的区别哦.^_^
Class类描述的信息:类的名字,类的访问数形.类所属的包名,字段名称的列表/方法名称的列表,等等.
学习反射之前,就要先明确Class这个类.
如何得到各个字节码对应的实例对象(Class类型)
1,类名.class 例如,System.class
2,对象.getClass() 例如, new Data().getClass();
3,Class.forName("类名"),例如Class.forName("java.util.Date");
9个预定义Class实例对象:
boolean byte char short int long float double void
判断是否为基本类型用.isPrimtive();
数据类型的Class实例对象
Class.isArray();
总之:只要是在源程序中出现的类型,都有各自的Class实例对象,例如int[] void
反射:就是把Java类中的各个成分映射成相应的Java类
需要掌握的包括:
Filed(成员变量),Method(方法),Contructor(构造方法),Package(包)
并不是说用这些方法,而是用这些类型中的一个方法来表达,
比如
System.exit();
System.getProperties();
上面的方法都可以用一个类型表示,Method
Method-->methodObj1
Method-->methodObj2
一个类中的每个成员都可以用相应的反射API类的一个实例对象来表示.
得到某个类所有的构造方法:
Constructor[] constructor = Class.forName("java.lang.String").getConstructors();
得到某个类一个构造方法://.getConstructor(参数.class,/*可以是可变参数*/)//如果没有可变参数JDK1.4以前.可以传入的是一个数组
Constructor constructor = Class.forName("java.lang.String").getConstructor(StringBuffer.class);
注意,
1,想要得到某一参数的类型,
2,再调用这个方法的时候也要传递同样类型的对象.
创建实例对象:通常方法:String str = new String(new StringBuilder("abc");
------------:反射方法:String str = (String)constructor.newInstance(new StringBuilder("abc"));
代码演示:
//new String(new StringBuilder("abc"));下面利用反射写一个与本行一样的代码
Constructor constructor1 = String.class.getConstructor(StringBuilder.class);
String str3 = (String)constructor1.newInstance(new StringBuilder("abc"));
System.out.println(str3.charAt(1));
Class.newInstance()方法
例子:String obj = (String)Class.forName("java.lang.String").newInstance();
该方法内部先得到默认的构造方法,然后该构造方法创建实例对象.
该方法内部的具体代码是怎样实现的呢?用到了缓存机制来保存默认构造方法的对象.
Field类代表某个类中的一个成员变量
演示用eclipse自动生成Java类的构造方法
问题:得到的Field对象是对应到类上面的成员变量,还是对应到对象上的成员变量?类只有一个,而该类的实例对象有多个,如果是与对象关联,哪关联的是哪个对象呢?所以字段fieldX 代表的是x的定义,而不是具体的x变量。
为了来演示这个成员变量 要自己定义一个类,这个类里边写两个成员变量,
public class RefiectPoint{
private int x;
public int y;
public RefiectPoint(int x,int y){
super();
this.x = x;
this.y = y;
}
} 有了这个类后对其进行反射
Field类的作用:代表字节码里边的一个变量 不代表某个对象身上的变量 我们在知道有y这个变量后,在各个对象上去取对象身上那个y
反射的作用 换掉一个对象里的字段 可以改变对象的值, 你在配置文件里配置了很多东西,我自动扫描你的文件,将你一写内置文件的配置换掉
Method类代表某个类中的一个成员方法 不是一个对象身上的方法
得到类中的某一个方法:
例子: Method charAt = Class.forName("java.lang.String").getMethod("charAt", int.class);
调用方法:
通常方式:System.out.println(str.charAt(1));
反射方式: System.out.println(charAt.invoke(str, 1));
如果传递给Method对象的invoke()方法的第一个参数为null,这有着什么样的意义呢?说明该Method对象对应的是一个静态方法!
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})形式。 这个数组长度为1 里头装一个integer对象 值为1
Method类代表某个类中的一个成员方法 不是一个对象身上的方法 可以拿着这个方法去调用类中的对象 方法和对象时没有关系的 我们在调用这个方法时必须通过某个对象去调用,你得到了方法 这个方法和对象没有关系 而紧跟着调用某个对象身上的方法 先得到方法,然后再针对某个对象去调用这个方法
//str1.charAt(1); 现在想干的事是 调用str1身上的charAt(1)方法
Method methodcharAt=String.class.,getMethod("charAt",int.class)
这个方法是从String字节码身上拿出来的,getMethod这个方法接收两个参数,第一个参数是方法名字,第二个参数是(一个类里面同名字的方法,有多种重载形式,你到底想从这个多个重载方法当中选取哪一个 你平时写程序时靠什么来识别的,靠参数的列表,列表就包括了列数和类型 这里每一个参数类型都对应一个class来表示, 到底有多少个参数就看你在此处写多少个class 只有一个参数 int)
用反射进行调用
System.out.println(methodCharAt.invoke(str1,1)
调用一个方法一定是在某个对象身上 第一个参数就是那个字符串对象,在这个字符串对象身上调用CharAt 第二个是 你调用charAt 方法的时候,要传一个参数进去, 得到的里边有几个参数 这里也得有几个参数int.class
这就是由反射的方式得到这个字节码当中的方法,再拿这个方法作用于某个对象,invoke表示调用 调用这个方法, invoke这个方法执行调用的动作,
invoke是这个方法对象身上的方法 方法的调用
画圆 这个方法 画那个动作在圆身上
人在黑板上画圆,三个对象,人 黑板 圆 画圆时需要哪些参数 信息 需要圆心和半径,圆心和半径是圆身上的,那画圆这个方法要用到圆心和半径, 圆心和半径是私有的,如果你将画圆这个方法分配给了人,通过人要去访问圆里边的私有方法,不合适,通过黑板也不合适,只有分配给圆,圆有一个动作叫画我, 画是我的动作,我才知道怎么画,
所以你调用的时候会感到别扭,circle.draw();这时给圆发信号 把自己画出来,你自己知道怎么画 我不知道
列车司机把列车给刹住了,想一想,列车司机有这么大的功力吗?
他只是踩了离合器,实际上是在给列车发出信号,你停车吧,你的离合器系统就开始运作,你的发动机熄火,所以是列车停车,司机给列车发信号,这个停车的动作只有列车才能干的了,所以画圆的动作只有圆能做的了,比如关门,谁把门关上,门 你只是推了一下,不是你关的,是它自己旋转,给关上的
面向对象其实非常简单:只要把变量搞成私有的,如果谁要操作这个变量,那么这个变量在谁身上,方法就应该在谁身上。这叫专家模式 谁拥有数据,谁就是干这个的专家, 那么这个方法就应该分配给谁
所以你看到的这个invoke是这个methodCharAt方法的invoke 但是调用invoke的时候是str1对象身上调用 一调用还要给参数
invoke(null,1) 若接收的方法为null 这时此方法是静态的 或者说 又一个静态方法 你想调用, 在这里写上null 因为静态方法调用时不需要对象, 不需要对象肯定是静态方法,
目标:
写一个程序,这个程序能够根据用户提供的类名,去执行该类中的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的语法解释,因此会出现参数类型不对的问题。
解决办法:
mainMethod.invoke(null,new Object[]{new String[]{"xxx"}});
mainMethod.invoke(null,(Object)new String[]{"xxx"});编译器会作特殊处理,编译时不把参数当作数组看待,也就不会数组打散成若干个参数了
我给你的数组,你不会当作参数,而是把其中的内容当作参数。
Class clazz = Class.forName(arg[0]);
Method mMain = clazz.getMethod("main", String[].class);
mMain.invoke(null,new Object[]{new String[]{"aaa","bbb"}});
mMain.invoke(null,(Object)new String[]{"aaa","bbb"});
}做一个程序 调用这个main方法
平时 TestArguments.main(new String[]{"111","222","333"}); 还可以传参数
这就是在程序里面用静态代码的方式直接调用它的main方法
直接调用 TestArguments类的main方法, newString类型的数组就搞定了
首先明白一个问题 为什么要用反射的 方式调用main方法
我并不知道要调用的那个类的名字, 你在执行这个main方法时同样给那个main方法中传进来一些参数, 而这个方法中就带有说 你去启动哪个类,假设里边第一个参数就是那个类的名字, 你告诉我 要去执行哪个类,我知道args[0]就是要启动的那个String className=args[0]; 类名就是String startingclassName=args[0];即将启动的className 那么我的源程序里边就没有出现到底是哪个类名,你通过一个参数给我说执行a这个类,我就执行a这个类,你在运行时说执行b这个类,我就执行b这个类,我的源程序中根本就不知道要执行哪个类,接下来你把一个类给我了,我知道这个类里面一定有一个方法
Method mainMethod = Class.forName(startingClassName).getMethod(name,parameterType) ("main",String[].class)
接收一个参数 并且是一个String类型的参数
接下来就要去调用main方法
mainMethod.invoke(null,new String[]{"111","222","333"});
静态的不需要传递对象,不通过对象就调用这个方法 要传递上面的参数 这样会报错 数组角标空指针异常
jdk1.5为了兼容jdk1.4, 当你给它一个字符串数组,(这就相当于object数组)。当收到一个object数组后不会将其当成一个参数,会将数组以包的形式打开,将打开的东西中的每一个元素分别作为一个参数(以数组的角度看就是一个参数,若将其看成一包东西就是好多个参数)
mainMethod.invoke(null,new Object[]{new String[]{"111","222","333"}});
这时再打一个包,new一个数组 这个数组里面装的第一个元素就是一个 数组 每个数组的父类都是object 就是每个数组都是object 是一个对象 现在给你一包东西 一打开 是一个数组
就是说 会将你拆开,这时就先把整个数组装成一个包,你拆包,露出来的就是数组
mainMethod.invoke(null,(Object)[]new String[]{"111","222","333"});
黎老师方法
因为数组也是一个Object 将其强制转换成Object(Object)这样写就相当于在和编译器说,我给你的是一个对象,不是一个数组,别拆包
说明类方法如何调用:因为我们要传一个数组,而数组在jdk1.4中被当做多个参数,我们想办法让其不让当做多个参数,
一种是 把数组打包成另外一个数组 你拆完一层皮后剩下来的就是那个数组 还有一种就是直接类型转换 还是当成object不要拆
具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象。
代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。
基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又可以当做Object[]类型使用。
Arrays.asList()方法处理int[]和String[]时的差异。
Array工具类用于完成对数组的反射操作。
数组也是一种类型,由jdk帮助文档能够知道数组的类型 每一个数组都属于同一个class 如果你用反射,反射出来的字节码都是同一个(具有相同的元素类型以及具有相同的维度)
Object[] aObj4 = a3; //a3是一个数组的数组,假设将其当做一个数组,=左边的object[]就等于第二维的那个数组 把a3 当做一个数组来看待 它里边装的就是int类型的一维数组 而这个int类型的一维数组就是object类 这表示一个数组,数组里边装的是object 也可以将其理解成 有一个数组,数组里头装的是int类型的数组,就等效于有一个数组,数组里边装的是object
Object[] aObj5 = a4; //这个数组里边装的是String String也是Object
arrays类 对数组进行操作的类
转换成list对象 aslist
asList
public static List asList{object[] a} 后面结束的是object[] 如果是一个String类型的数组传进来,就按jdk1.4编译成List 如果传的是int类型,人家觉得跟这个对象对不上 就让你回1.5去处理
public static <T> List<T> asList(T...a) 不当做object数组类型 只当做一个object 就等效于一个参数 刚才的String类型的数组,符合1.4的 就把String数组里边的每一个元素列举出来放到list中去 如果你是int类型的数组, 不符合就按1.5的走,当成一个object 一个参数
上面只是因为使用容器不同造成打印结果的集合长度不同
ArrayList是一种有顺序的集合 就相当于一种数组,当你要放一个对象要进来的时候,它首先找到第一个空位置放进去,不是真正的把对象放进去了 而是将对象的引用在数组中记住了 当你再放一个对象进去时 它会按顺序找到第二个位置 当你放第三个时 第三个与第一个相同 还放的进去,就相当于 每放一下里边就多一个引用变量,好多个引用变量 引用的是同一个对象 没关系 它是按照先后顺序依次放进去,这样就是有顺序的 你可以明确的说从第几个取,有位置顺序 甚至可以插队 这个顺序不是比较顺序(排序),而是指位置顺序 每放一个 每一个都能放进去
HashSet(); 你要放进去的时候,先判断里面有没有这个对象,就是比较两个对象是否相等,如果一旦有了 就不放;如果你要想放一个对象覆盖掉原来的对象(你必须要把原来的删除掉remove)再把新的给插进去
如果想要让pt1和pt3相等 必须要去写equals方法 否则 默认 equals比较的是hashcode的值 通常是由内存地址换算出来的
这是两个独立的对象,==肯定不等,equals我们没有覆盖 所以也不等
面试题
hashCode方法的作用 如果想查找一个集合中是否包含有某个对象,大概的程序代码怎么写呢?你通常是逐一取出每个元素与要查找的对象进行比较,当发现某个元素与要查找的对象进行equals方法比较的结果相等时,则停止继续查找并返回肯定的信息,否则,返回否定的信息。如果一个集合中有很多歌元素,譬如一万个元素,并且没有包含要查找的对象时,则意味着你的程序需要从该集合中取出一万个元素进行逐一比较才能得到结论。有人发明了一种哈希算法来提高从集合中查找元素的效果,这种方式将集合分成若干个存储区域,根据一个对象的哈希码就可以确定该对象应该存储在哪个区域
只有说文件的存储集合必须存储在这种hash集合当中才有这种价值
HashSet就是采用哈希算法存取对象的集合,它内部采用对某个数字n进行取余的方式对哈希吗进行分组和划分对象的存储区域。Object类中共蒂尼了一个hashCode()方法来返回每个java对象的哈希吗。当从HashSet集合中查找某个对象时,java系统首先调用对象的hashCode()方法获得该对象的哈希码,然后根据哈希吗找到相应的存储区域,最后取出该存储区域内的每个元素与该对象进行equals方法比较,这样不用遍历集合中的所有元素就可以得到结论,可见,HashSet集合具有很好的对象检索性能,但是,HashSet集合存储对象的效率相对要低些,因为向hashset集合中添加一个对象时,要先计算出对象的哈希吗和根据这个哈希吗确定对象在集合中的存放位置
没有实现hashcode算法就=3
因为如果 这两个对象比较equals比较相等了 但是你算出来的hashcode值是按照你的内存地址算的 这两个本来该认为相同的对象,分别被存放到了不同的区域,当我要去找这个对象的时候,我在我这个区域里面找,不在那个区域里边找,那个区域确实存在一个跟我相等的对象,但是我不去那个区域里边找,我就被放进数组中去了。
为了让相等的对象也放在相同的区域,所以人家就有一个说法 如果两个对象equals相等的话,应该按照他们的hashcode也相等,如果对象不存到hash集合里边,就没必要搞hashcode了
当一个对象被存储进hashset集合中以后,就不能够修改这个对象中的那些参与计算哈希值的字段了,否则,对象修改后的哈希值与最初存储进hashset集合中时的哈希值就不同了,在这种情况下,即使在contains方法使用该对象的当前引用作为的参数去hashset集合中检索对象,也将返回找不到对象的结果,这也会导致无法从hashset集合中单独删除当前对象,从而造成内存泄露
java中在内存泄露吗,为什么?
所谓内存泄露就是这个对象我不要用了 却还在一直占用内存空间,没有被释放,这就叫做内存泄露
举例就是上面的例子
什么是框架,例如,我们要写程序扫描.java文件中的注解,要解决哪些问题:读取每一样,在每一个中查找@,找到的@再去查询一个列表,如果@后的内容出现在了列表中,就说明这是一个我能处理和想处理的注解,否则,就说明它不是一个注解或者说至少不是一个我感兴趣和能处理的注解。接着就编写处理这个注解的相关代码。现在sun提供了一个apt框架,它会完成所有前期工作,只需要我们提供能够处理的注解列表,以及处理这些注解的代码。Apt框找到我们感兴趣的注解后通知或调用我们的处理代码去处理。
你做的门调用锁,锁是工具,你做的门被房子调用,房子是框架,房子和锁都是别人提供的
程序中不处理异常,而是main方法声明抛出异常,便于大家可以集中看主要的关键代码。
Class类也提供getResourceAsStream方法的比喻:如果你每次都找我给你商店买可乐,那我还不如直接向你买可乐,即直接提供一个买可乐的方法给你。
String startingclassName=args[0];就是要调用某个类的main方法,而到底调用哪个类的main方法,在写程序的时候是不知道的,而是等程序运行起来以后,你再传递一个字符串给我, 这个字符串对应的这个类和现在这个类哪个先写出来的 args这个类还没写出来,源程序就编好了(我要调用你的类,结果我写程序的时候 你的类还没有写,我就可以调,只要你等我运行的时候写出来就可以,在我写的时候你还没有写出来,没关系 框架 用strans做框架, 在还没有用strans做项目的时候 框架就已经写完了 在用strans做项目时就写了好多个我们自己的类,我们写的类在运行的时候给strans框架区调用 框架先写完 我们的程序后写 这就是反射的一个好处)
大家以后在用别人写的类 有两种使用方式:一种是你去调用别人的类,还有一种是 别人的类来调用你的类 不管怎么弄 都是你在用别人的类 , 别人调用你 也算你用别人的 你用strans框架 是不是 框架在调用你 这两种有区别 一个叫框架 一个叫工具 举个买房子的例子
框架和工具类的区别: 都是别人写的 但是用法不一样 一个是 人家调用你 一个是你调用人家
大家做的一个一个的strans项目,每个项目都不一样,但是每个人都做的很快,因为大家首先上来就是在一个框架基础上开始干(在一个半成品的基础上开始),
人家找你们开发用框架 因为做事效率高,项目完成效率高
框架要解决的核心问题是: 要解决 我若干年前写程序 能够调用你若干年后写的程序 不能直接new某个对象,只能.class().forName()一个字符串,那个字符串等运行的时候再给我 这就是反射
配置文件: new file 名字:config properties 里边写 className=java.util.ArrayList 4
className=java.util.HashSet 2
等程序最终运行的时候,就不用改java源程序,只要改这个文件,那个类就换了
在运行的时候,我把程序交给了你,你作为客户你没有javac,不能改源文件,但是你又记事本,将这个文件改一下就可以了。
配置文件要放在那里?要放在工程下面
程序开发完后,不能将整个java目录给对方,只要将.class文件打包成jar包给对方就行,在实际开发中没有用相对路径搞得,你不知道这个相对路径是相对于谁
c:\Documents and Settings\ibm>java.MyClass xx.file 在这个路径下用到了xx.file文件,xx文件是相对于MyClass文件还是java.exe 谁都不是,而是相对于当前工作目录ibm下 这时就感觉到这个相对路径是飘忽不定的,要用就用绝对路径
而用绝对路径又出现一个问题: 一定要记住用完整的路径,但完整的路径不是硬编码,而是运算出来的
InputStream ips = new FileInputStream("d\\config.properties"); 将其放在d盘,结果人家机器上小硬盘 没有d盘,只有c盘, 这是一种解决方案,绝对路径,但是绝对路径这个d盘,不是硬编码写进去的。而是用某种方法get出来的。 譬如说你在一个配置文件里边, 而对方在系统的某个地方进行配置,说config.properties的位置 所在的目录,配完后,就可以去读 也就是说用户想把它放在哪个位置都可以,放完后,需要在配置文件中写一下说这个文件放在了哪里 这样我的程序就可以运算出来那个绝对路径 学javaweb时就会学到这种方式 得到绝对路径
在javaweb中,你的东西肯定是放在你的web项目里边,得到web项目在硬盘上的对应的具体目录,getRealPath;而你的配置文件肯定是在web项目文件内部,你得到了web项目绝对位置,再拼上你内部那个位置就拼到了一个真实完整的位置,得到你总的目录在硬盘上对应的绝对位置
类加载器:
每一个.class文件在使用时都要加载到内存中来,就是说一定要有个东西,将硬盘上的.class文件搞到内存里面来,
既然类加载器能够加载class文件 那是不是也能够加载普通文件呢
InputString ips = eefiectTest2.class.getClassLoader().getResourceAsStream("cn/itcast/day1/config.properties");//在classpath指定的目录下,逐一的去查找你要加载的那个文件,
InputString ips = RefiectTest2.class.getResourceAsStream("config.properties");
联系客服