1、关闭一个窗体可以用 dispose()
2、jvm默认的内存大小为64M
3、equals比较应该这样
String a=null;
a.equals("abc"); 这样会出现空指针异常
"abc".equals(a);这样就不会
4、jad -o -a -s xxx.java xxx.class 反编译class字节码文件【使用jad反编译的好处之一就是可以同时生成字节码和源代码】
5、String与StringBuffer、StringBuilder比较
如果使用普通的字符串拼接形式【+】,jvm在编译时会把+转换成StringBuilder对象,然后在调用append方法,所以当要频繁拼接时应当使用StringBuilder,且不应把+与StringBuilder混合使用,这样只会产生更多的对象,对于StringBuffer与StringBuilder大致一样,只是StringBuffer是线程安全的,StringBuilder是效益更高的
6、java中模拟发送http协议可以用URL类与HttpURLConnection类来发送,如果要发送文件到web应用可用,socket来代替HttpURLConnection,因为HttpURLConnection内部使用了缓存
---------------------------集合-------------------------
![]()
1、基本每个集合类【不包含Map接口下的类】都提供了一个iterator的迭代器用来遍历,在遍历过程中只能通过Iteractor接口提供的remove来删除元素
2、list与set区别:
1、set集合不允许包含相同的元素
2、list判断二个对象相同是根据equals来的,set接口中的元素是无序的,循环来遍历时也是无序的,而list集合则反之
3、HashSet集合判断两个元素相等的标准是两个对象通过equals()来比较,并且两个对象的hashCode()方法返回值也相等【hashCode的值决定该对象在HashSet的存储位置】
4、TreeSet里的对象必须实现Compareble接口,而且对象必须是同一个类的
判断两个元素相等的标准是:通过Comparator比较两个元素返回了0,这样TreeSet不会把第二个元素添加到集合去了
5、List判断两个对象相等只要通过equals方法比较返回true即可
6、ArrayList与Vector类都是基于数组实现的List类
7、HaspMap判断key的标准跟HashSet一样,两个对象通过equals()来比较,并且两个对象的hashCode()方法返回值也相等【可以直接根据key的地址获得value的地址】
8、Properties可以用来读写属性文件
9、java为所有集合类提供了一个Collections工具包
10、集合里只能存对象,所以当把一个基本类型传进来时会自动装箱
11、Array 读快写慢 LinkedList改快读慢 Hash 两者之间
12、与Arrylist相比:LinkedList 适用在频繁修改的情况用
Vector 适用于线程同步
13、源码心得:
1、HashMap与HashTable的区别:
1、HashMap能存在空键值对,而Hashtable不能
2、HashMap没有contains()方法,而Hashtable有
3、HashMap是线程不安全的
2、LinkedList是基于一个Entry对象双向链表实现的,他的第一个元素的值[element]永远是null,而且他的第一个元素的next与最后一个的previous是关联,且LinkedList的listIterator迭代器可以向前或向后
3、一般的集合做修改时都有返回修改前的oldvlaue值
4、HashMap是无序的,LinkedHashMap是有序的
===================IO start===================
1、file
exists 文件是否存在
createNewFile 创建文件
mkdir 创建文件夹【如果filePath为多级文件夹则不会创建成功】
mkdris 创建多级文件夹
isDirectory 是否为一个目录
list(FileNameFilter fileter) 可通过匿名内部类遍历文件
RandomAccessFile 可以读写,应用场景多线程下载
2、流
按方向:输入流 输出流
按单位:字节流 字符流
FileInputStream
read
FileOutputStream
write
3、一个输入流只能读一次
4、文本文件用字符流来处理,资源文件用字节流来处理
5、处理流,构造器数据不是一个物理节点,而是已经存在的流
6、InputStreaReader转换流一般配合System.in使用
7、对象序列化:一个对象要想能够实现序列化,必须实现Serializable接口或在变量前加上transient不加入序列化
8、PrintWriter流可以装饰流也可以传入文件,不用close也可以打印【二参构造器如果设为true,则自动刷新内存】
9、为什么JAVA只提供了InpuStreamReader,而没有提供ReaderStreamInput:
众所周知,字节流比字符流使用范围更广,但字符流比字节流操作方便,如果有个流已经是字符流了,也就是说一个用起来更方便的流,为什么要转换字节流,反之,
如果现在有一个字节流,但我们知道流的内容是文本内容,那些把它转换成字符流来处理会更方便一些
10、重定向标准输入/输出
11、JAVA虚拟机读写其他进程的数据【Process对象】
12、RandomAccessFile类随机访问
13、对象序列化:
1、必须实现Serializable接口或Externalizable接口【自定义序列化】
2、反序列化机制无须通过构造器来初始化Java对象
3、Field前面加transient则指定该Field不被序列化
3、序列化算法 1、所有保存到磁盘中的对象都有一个序列化编号
2、当程序试图序列化一个对象时,程序将先检查该对象是否已经被序列过,只有对象从未(在本次虚拟机中)被序列化,否则将直接输出一个序列化编号
4、自定义序列化
1、可通过自定义三个方法【必须是private】【writeObject(),readObject(),readeObjectNoData()】自定义序列化的算法【保证Field的安全】,反序列化方式【readObject的顺序应该和writeObject顺序一致】
2、还有一种更彻底的自定义序列化,可以把一个对象序列化成想要的类型,需重写 writeReplace()方法
5、关于serialVersionUID,用于标识该Java类的序列化版本,以防类的成员被修改反序列化不成功
--------------------------多线程【轻量级进程】-------------------------------------
1、实现多线程的三种方法:
1、实现Runnable接口【推荐,因为是接口,线程类可以去继承其他类,可以操作同一份资源】
获得当前线程只能Thread.currentThread()
2、实现Callable接口
3、继承Thread类【此方式创建的线程类之间不能共享线程类的实例变量】
2、关闭线程 一般都用一个tag变量来控制循环
10、线程间交换数据用PipedReader与PipedWriter
11、守护线程【后台线程】
【如JVM回收线程】 【如果所有前台线程死亡,后台线程会自动死亡】 在线程就绪状态之前(调用start()之前)调用
线程.setDaemon(true)
12、类锁:将类的静态成员函数声明为 synchronized ,以控制其对类的静态成员变量的访问
14、并发性:在同一时刻只能有一条指令执行,但多个进程指令被快速轮换执行,使得在宏观上具有多个进程同时执行的效果
并行性:在同一时刻,有多条指令在多个处理器上同时执行
15、生命周期:新建 -> 就绪 -> 运行 -> 阻塞 -> 死亡
新建:new关键字时创建一个线程,此时的线程对象没有表现出任何纯种的动态特征
就绪:当线程对象调用了start()方法之后,处于这个状态中的线程并没有开始运行,只是表示该线程可以运行了
运行:处于就绪状态的线程获得了CPU,开始执行run()方法的线程执行体
阻塞:当线程调用了sleep()、调用了阻塞式IO方法、
等待同步锁
、
等待某个通知、调用了suspend()挂起,且阻塞线程
被解除后会在合适的时候重新进入就绪状态
16、不要试图对一个线程对象调用二次以上start( )
17、线程控制:
1、join线程:让一个线程等待另一个线程完成后在执行的方法
2、sleep( ):线程进入阻塞状态
【只会给其他线程执行的机会,不会理会其他线程的优先级】
3、yield():与sleep相似,但该方法只是让正在执行的线程暂停,转入就绪状态【只会给优先级相同或优先级更高的线程执行机会】
18、线程同步的几种方式:线程会进入等待池,然后进入锁池,然后进入就绪状态
1、同步代码块
synchronized (obj|class){ }
任何时刻只能有一个线程可以获得对同步监视器的锁定【获得锁旗标】,代码块结束后,该线程会自动释放
synchronized
代码块里要调用外部成员,外部成员必须是final的
2、同步方法:因为监视器监视的对象就是this,所以
只要有一个线程还在调用synchronized方法,其它线程就不允许访问这个类的所有的synchronized方法
3、同步锁:Lock【自定义对象的锁定与释放】
19、线程通信的几种方式:
1、传统的线程通信:Object的wait() notify() notifyAll(),这三个方法可以由同步监视器对象来调用,一个是
同步方法的this , 一个是同步代码块括号的obj【且只能在同步监视器内调用】
2、PipeInputStream/PipeOutputStream
20、线程局部变量[ThreadLocal]:为每一个使用该变量的线程都提供一个变量值的副本,使每一个线程都可以独立地改变自己的副本,而不会和其他线程的副本冲突
21、JDK提供的String,StringBuffer就是为了照顾单线程和多线程环境所提供的类
-----------------------------------泛型[菱形]-------------------------------------------
1、并不存在泛型类,通过反射机制可以绕过
List<String> li=new ArrayList<>();
List<Integer> li2 =new ArrayList<>();
Boolean bl=li.getClass() ==li2.getClass(); //返回true
通过上面这段代码可得知,系统并没有为List<String>生成新的class文件,而且也不会把AraayList<String>当成新类来处理
因此在静态方法、静态初始化块、静态变量的声明和初始化中不允许使用泛型,instanceof运算符后也不能使用
2、通配符上限:<? extends Object>表示所有Object的子类与Objce都可以
<? extends Number & Object>
通配符下限:<? super List> 表示是List的基类与List都可以
3、方法泛型,
public <T> void test(T a,List<T> list){}
test(new String(),new List<Integer>());
上面的new List<Integer>()与定义的test(T a,List<T> list)进行比较【只比较泛型参数】,该T类型形参代表的实际类型是Integer
4、泛型构造器
class MyClass<E>{
public <T> MyClass(T t) {
System.out.println("t参数的值为:" + t);
}
}
// MyClass类声明中的E形参是String类型。
// 泛型构造器中声明的T形参是Integer类型
MyClass<String> mc1 = new MyClass<>(5);
// 显式指定泛型构造器中声明的T形参是Integer类型,
MyClass<String> mc2 = new <Integer> MyClass<String>(5);
// MyClass类声明中的E形参是String类型。
// 如果显式指定泛型构造器中声明的T形参是Integer类型
// 此时就不能使用"菱形"语法,下面代码是错的。
//MyClass<String> mc3 = new <Integer> MyClass<>(5);
5、泛型与方法的重载
6、泛型擦除:当把一个具有泛型信息的对象付给给另一个没有泛型信息的变量时,所有在尖括号之间的类型信息都将被扔掉【默认是声明该参数时指定的第一个上限类型】
List<Integer> li = new ArrayList<>();
li.add(6);
li.add(9);
List list = li;
// 下面代码引起“未经检查的转换”的警告,编译、运行时完全正常
List<String> ls = list; // ①
// 但只要访问ls里的元素,如下面代码将引起运行时异常。
System.out.println(ls.get(0));
7、java不支持泛型数组,且支持引用类型
8、等号两边实际的参数类型必须相等,即使是继承关系也不行
List<Object> list=new ArrayList<String>()
------------------------------JDBC-----------------------------------
步骤 1、加载驱动 Class.forName("driver位置");
2、获得连接对象 DriverManager.getConnection("url","用户名","密码");
url:serversql 为 jdbc:sqlserver://localhost:1433; databaseName=student
mysql 为 jdbc:mysql://localhost:3306/mysql?useUnicode=true&characterEncoding=utf-8,【设置编码,与数据库一致】
Oracle 为
jdbc:oracle:thin:@localhost:1521:orcl
3、创建语句对象 连接对象.createStetament();
4、执行语句 语句对象.executUpdate("执行语句");
语句对象.executQuery("执行语句"); [返回ResultSet结果集]
1、createStatement() 执行对象
2、prepareStatement() 语句格式化
3、prepareCall() 调用存储过程
4、addBatch() 批处理
5、PreparedStatement参数格式化,可防SQL注入
6、可滚动结果集 con.
prepareStatement(sql, ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
--------------------------反射-------------------------------------
1、反射构造方法
Class c=Class.forName("反射.Person");
cs=c.getConstructor(int.class);//调用有参数的,传入相应的参数类型
cs.newInstance(1); //传入参数的值
2、在反射中,可以通过
setAccessible(true)
访问暴力访问私有的成员
3、反射调用方法
//public int run()
第一种:
Method[] m=c.getMethods(); //获得所有方法的对象
for(int i=0;i<m.length;i++){
if(m[i].getName().equalsIgnoreCase("run")){ //反射方法的名字
int res=(int)m[i].invoke(p, null); //调用
}
}
第二种:
Method me=c.getMethod("run", null);//方法名 参数类型
int res=(int)me.invoke(p, null);//p为对象,null为无参数
//public int run(String name)
me=c.getMethod("run", String.class);
me.invoke(p, "这是调用方法传入的参数");
反射静态成员,只要把传入的对象变为null就行了
反射私有成员,只要把对象的setAccessible(true)就行
反射main方法时,传入参数用m1.invoke(null,(Object)new String[]{"aa","bb"});来传参数
5、类初始化步骤:
1、类加载:
将类的class文件读入内存,并为之创建一个java.lang.Class对象
1、BootStrap 加载
Java\jdk1.7.0_01\jre\lib\
rt.jar中用到的类
2、ExClassLoader 加载
Java\jdk1.7.0_01\jre\lib\ext\*.jar所有用到的类
3、AppClassLoader 加载用户自定义的类
4、自定义加载器
2、连接:验证、准备、解析
3、成员初始化
6、委托机制
7、
获得泛型的类型
Type type = UserService.class.getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType ptype = (ParameterizedType) type;
System.out.println(ptype.getActualTypeArguments()[0]);
}
--------------------------Annotation注解------------------------------------
1、分为二大类
1、标记Annotation,仅利用自身的存在与否来为我们提供信息
2、元数据Annotation,包含成员变量,能更多的描述这个Annotation的信息
2、一个Annotation标记要想在运行时被保留得在Annotation类中加上 @ Retention(RetentionPolicy.RUNTIME) //指定Annotation注解可以保留到运行时(JVM会提取Annotation)
3、Retention用于保留
Target用于修饰
===================正则 start===================[软件包 java.util.regex ]
1、String类里有个默认的matches方法
matches 匹配整个字符串
find() 尝试查找与该模式匹配的输入序列的下一个子序列
reset() 重置匹配器
start() 返回查找到的位置
3、替换 replaceAll(str)
appendReplacement()针对每次找到的子序列进行替换
4、分组[在匹配符中用()来分组]
用group()来获得整个分组
用group(num)来获得第num个分组的匹配子序列
--匹配符
. 代表任意一个字符
* 代表出现零次或者多次
+ 代表出现一次或者多次
? 零个或者一个
C{n} C正好出现n次
C{n,} C至少出现n次
C{n,m} C至少出现n次,但不超过m次
边界
范围
[abc123] 取a,b,c,1,2,3的一个
[^abc] 取除了abc的一个
[a-zA-Z] or [a-z] | [A-Z] or [a-z[A-Z]] 取a-z或A-Z中间的一个
[A-Z&&[RFG]] 取A-Z中间并且只能为RFG
\d 一个数字
\D 非数字
\w 一个字母
\W 非字母
非捕获
(?i) 相当于Pattern.compile("java",Pattern.CASE_INSENSITIVE); 不区分大小写