基础知识
随机数
- Random使用,bound即上界,seed即随机数种子,代表时间,多次执行程序,Random产生的序列始终是一个序列。(网上又说以47为随机数种子产生随机数的随即率最大,对这句话不是很理解)
1 | Random rand= new Random(47);//seed: 47 |
Math.random(),该方法是产生0和1之间(包括0,单不包括1)的一个随机double值。
生成一个大随机数,下面例子BigInteger有256位
1 | BigInteger A = new BigInteger(256, new Random()); |
循环
Foreach
这是一种从Java SE5开始的新的更简洁的for语法用于数组与容器,表示不必创建int变量去对由访问项构成的序列进行计数,foreach将自动产生每一项。
1 | Random rand=new Random(47); |
文件流
序列化与反序列化
什么是序列化与反序列化
对象序列化的定义是,将对象转态转化为字节流的过程,可以将其保存到磁盘文件或通过网络发送到任何其他程序,从字节流创建对象的相反的过程称为反序列化,并且创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。(这里可能是这个意思,比如在Java上将数据序列化存入文件中,而用C#又可以将文件中字节流反序列化为原来的数据)
简单的说,把对象转换为字节序列的过程称为对象的序列化。把字节序列恢复为对象的过程称为对象的反序列化。
具体体现
首先需要使用Serializable关键字实现接口;注意对于存在类的继承关系的接口实现,只需实现父类的接口即可;
- 序列化:创建对象输出流,包装一个某种类型的目标输入流,如文件输入流,然后通过对象输入流的writeObject()方法写对象。
- 反序列化:创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流,然后通过对象输入流的readObject()方法读取对象。
1 | public class Person implements Serializable {//父类序列化 |
序列化并以覆盖形式写入。
1 | public static void AssistantInformationInput(){ |
序列化并以追加形式多次写入。对象序列化不能向普通文件一样直接追加对象。
在new ObjectOutputStream对象的时候,会执行它的构造方法,在构造方法中有一个writeStreamHeader();语句会被执行,这个方法的功能就是在文件中写入文件头。如果你写的方法在一个文件中重复new了ObjectOutputStream对象,则每次执行构造函数的时候都会执行这个方法写上一个文件头。Java默认的对象序列化是每次写入对象都会写入一点头aced 0005(占4个字节),然后每次读取都读完头然后在读内容。解决方法就是先判断文件是否存在。如果不存在,就先创建文件。然后写了第一个对象,也写入了头aced 0005。追加的情况就是当判断文件存在时,把那个4个字节的头aced 0005截取掉,然后在把对象写入到文件。这样就实现了对象序列化的追加。(需要注意的是,并非是每次序列化追加写入都需要减掉4字节,而是每次创建对象流的时候需要减)
1 | public static void AssistantInformationInput(){ |
transient关键字
transient关键字标识的变量意味着不会被序列化。
输入流的几种常见形式
1 | public class Main { |
文件读写
1 | import java.io.*; |
泛型与集合
集合
迭代器
简单的说迭代器是用来帮助访问集合中的每个元素。所有的集合类(Set、Sequence、Queue,除了Map)都实现了迭代接口Iterable,Iterable接口只有一个方法。
1 | Iterator<T>iterator(); |
它返回一个在一组T类型元素上的迭代器,Iterator是一个接口类型,它的方法如下。
方法名称 | 作用 |
---|---|
hasNext() | 如果仍有元素可以迭代,则返回true |
E next() | 返回迭代的下一个元素 |
remove() | 迭代器指向的集合中移除迭代器返回的最后一个元素(可选操作) |
下面给出利用迭代器访问元素的实现
1 | Iterator<Acount>iterator=accounts.iterator(); |
集合实例名为accounts,包含的都是Accout类型的对象。
List
- list是有序,可以通过整数索引(从0开始)访问列表中的元素。
- 列表通常允许重复的元素。
- list接口提供了特殊的迭代器,称为ListIterator,除了允许Iterator接口提供的正常操作外,该迭代器还允许元素插入和替换,以及双向访问。
- 某些实现List接口的列表类,对是否允许null出现在列表中有着不同的规定。
ArrayList
ArrayList是基于数组的,在初始化ArrayList时,会构建空数组,ArrayList是无序的,是按添加顺序的进行排列,但是他有sort方法。
实现
1 | List<Integer>list=new ArrayList<>(); |
对于赋值右段的"<>",编译器可以自动推断出其应具备的类型。
字符串
字符串常量与字符串变量
首先java编译器对于字符串常量会创建一个对象;另外,字符串中所有字符都是Unicode字符,所以每个字符占两个字节;
在java中,字符串常量在内存中由编译器分配固定区域,而字符串变量只是一个引用,所以不能通过字符串变量对常量进行修改,即想要通过引用修改字符串是不可行的;
1 | String str = "hello world!"; |
如上面的操作只是修改了str的引用,并非修改了其值;
1 | String str = "hello world!"; |
而上面的操作,其实str和str1都是对同一个字符串常量的引用,在str1进行赋值时会自动在字符串常量池中检测是否有该串,若有就直接利用它,这样做的优点是减少了程序中需要存储的字符串的数量和空间;
字符串的比较
java里的字符串的比较有两种;str1.equals(str2)
,即判断str1的字符序列是否等于str2的字符序列,==
,判断两个对象是否引用同一个对象;另外还有str1.compareTo(str2)
,该方法用来判断str1、str2两个字符串的字典序大小关系;看下面代码即可;
1 | public class Main { |
注意new的使用,比如String s = new String("hello");
则是声明了一个对String的引用,然后分配一个内存空间,之后调用构造函数初始化该空间的值为"hello",然后将该地址的值赋给已创建的String的引用;String s= "hello"
,则是先去字符串常量池中寻找受否存在"hello",若有则直接使用它,使得引用s指向该字符串常量;(这一段是个人理解)
其他
String是一个不可变的对象,每次对于String进行操作或者使用其相关的一些函数,都可能会生成一个新的String的对象,所以如果需要经常对其进行操作,那么会反复生成大量的临时对象,这是非常浪费时间的;
内存
堆、栈、常量池等
- 常量池:未经new的常量
- 堆区:成员变量的引用,new出来的变量;成员变量的引用在堆区,是因为成员变量所属的对象在堆区,所以它也在堆区;
- 栈区:局部变量的引用;局部变量的引用在堆区,是因为局部变量不属于某一个对象,在调用时才被加载,所以在栈区;
细节
类
成员变量与方法
- Java的main方法一样要写在public修饰的类里, >main方法是JVM(java虚拟机)自动调用 > >JVM调用main方法的位置自然不会在某个类中、或某个包中,因此只有当main方法在公有级别上时,才对JVM可见,所以mian方法需要public修饰, > main方法所在的类也需要public修饰符。 > 另外由于main方法是所有程序的入口,也就是main被调用时没有任何对象创建,不通过对象调用某一方法,只有将该方法定义为静态方法,所以main方法是一个静态方法,既需要static修饰。 > JVM对于java程序已经是最底层,由它调用的方法的返回值已经没有任何地方可去,因此,main方法返回值为空,既需用void修饰。