Java编程学习笔记
⽬录
⼀、java基础知识总结
1. java final 关键字:
1).修饰类:当⽤final修饰⼀个类时,表明这个类不能被继承。也就是说,如果⼀个类你永远不会让他被继承,就可以⽤final进⾏修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员⽅法都会被隐式地指定为final⽅法。
2).修饰⽅法:下⾯这段话摘⾃《Java编程思想》第四版第143页:
  “使⽤final⽅法的原因有两个。第⼀个原因是把⽅法锁定,以防任何继承类修改它的含义;第⼆个原因是效率。在早期的Java实现版本中,会将final⽅法转为内嵌调⽤。但是如果⽅法过于庞⼤,可能看不到内嵌调⽤带来的任何性能提升。在最近的Java版本中,不需要使⽤final⽅法进⾏这些优化了。“
  因此,如果只有在想明确禁⽌ 该⽅法在⼦类中被覆盖的情况下才将⽅法设置为final的。
  注:类的private⽅法会隐式地被指定为final⽅法。
3).修饰变量:⽤final关键字修饰的变量,只能进⾏⼀次赋值操作,并且在⽣存期内不可以改变它的值。
2. java内部类:在Java中,可以将⼀个类定义在另⼀个类⾥⾯或者⼀个⽅法⾥⾯,这样的类称为内部类。⼴泛意义上的内部类⼀般来说包括这四种:成员内部类、局部内部类、匿名内部类和静态内部类。下⾯就先来了解⼀下这四种内部类的⽤法。
1).成员内部类:成员内部类是最普通的内部类,它的定义为位于另⼀个类的内部。在外部类中如果要访问成员内部类的成员,必须先创建⼀个成员内部类的对象,再通过指向这个对象的引⽤来访问。成员内部类是依附外部类⽽存在的,也就是说,如果要创建成员内部类的对象,前提是必须存在⼀个外部类的对象。创建成员内部类对象的⼀般⽅式如下:
学习java的学习方法public class Test {
public static void main(String[] args)  {
//第⼀种⽅式:
Outter outter = new Outter();
Outter.Inner inner = w Inner();  //必须通过Outter对象来创建
//第⼆种⽅式:
Outter.Inner inner1 = InnerInstance();
}
}
class Outter {
private Inner inner = null;
public Outter() {
}
public Inner getInnerInstance() {
if(inner == null)
inner = new Inner();
return inner;
}
class Inner {
public Inner() {
}
}
}
2). 局部内部类:局部内部类是定义在⼀个⽅法或者⼀个作⽤域⾥⾯的类,它和成员内部类的区别在于局部内部类的访问仅限于⽅法内或者该作⽤域内。
3). 匿名内部类:匿名内部类应该是平时我们编写代码时⽤得最多的,在编写事件监听的代码时使⽤匿名内部类不但⽅便,⽽且使代码更加容易维护。匿名内部类是唯⼀⼀种没有构造器的类。正因为其没有构造器,所以匿名内部类的使⽤范围⾮常有限,⼤部分匿名内部类⽤于接⼝回调。匿名内部类在编
译的时候由系统⾃动起名为Outter$1.class。⼀般来说,匿名内部类⽤于继承其他类或是实现接⼝,并不需要增加额外的⽅法,只是对继承⽅法的实现或是重写。
4). 静态内部类也是定义在另⼀个类⾥⾯的类,只不过在类的前⾯多了⼀个关键字static。静态内部类是不需要依赖于外部类的,这点和类的静态成员属性有点类似,并且它不能使⽤外部类的⾮static成员变量或者⽅法,这点很好理解,因为在没有外部类的对象的情况下,可以创建静态内部类的对象,如果允许访问外部类的⾮static成员就会产⽣⽭盾,因为外部类的⾮static成员必须依附于具体的对象。
3. String类继承⾃CharSequence接⼝,该接⼝主要有length()以及chatAt()⽅法。StringBuffer和StringBuilder类都继承⾃AbstractStringBuilder类,该类实现了Appendable和CharSequence接⼝,该类的append⽅法代码如下:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
count += len;
return this;
}
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {
if (srcBegin < 0) {
throw new StringIndexOutOfBoundsException(srcBegin);
}
if (srcEnd > value.length) {
throw new StringIndexOutOfBoundsException(srcEnd);
}
if (srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);
}
System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);
}
实际上是调⽤了System.arrayCopy()⽅法复制char数组。StringBuffer和StringBuilder类区别是StringBuffer类是线程安全的,每个⽅法前⾯都加了synchornized。
4. java 字符串反转⽅法: 1. 利⽤ StringBuffer 或 StringBuilder 的 reverse 成员⽅法,2. 利⽤ String 的 toCharArray ⽅法先将字符串转化为 char 类型数组,然后将各个字符进⾏重新拼接。3. 利⽤ String 的 CharAt ⽅法取出字符串中的各个字符:
5. 抽象类不⼀定需要abstract⽅法
6. private的概念是符合OOP(⾯向对象编程)的封装性,并不是为了⽅法的安全。setAccessible的潜在意义相信你⾃⼰能把控⾃⼰的代码。
7. und()理解:⾸先要注意的是它的返回值类型是long,如果 und(11.5f),那它的返回值类型就是int,这⼀点可以参考API
其次 Returns the closest long to the argument, with ties rounding to positive infinity
它返回的是⼀个最接近参数的long 值(例如:und(11.6) = 12;und(-11.6) = -12;und(-0.1) = 0;und(0.1) = 0),那如果出现向上向下距离⼀样的数值,⽐如题⽬中的11.5,该如何处理呢,别着急,看它的后半句话,with ties rounding to positive infinity(同时向正⽆穷⽅向取舍或者翻译成取较⼤的值,英语⽔平较差,只能翻译成这样了;
例⼦:  und(11.5) ,⾸先与 11.5最接近的有两个整数 11 和 12,取较⼤的那结果就是12;
然后它有三个特例:
1.如果参数为 NaN(⽆穷与⾮数值),那么结果为 0。
2.如果参数为负⽆穷⼤或任何⼩于等于 Long.MIN_VALUE 的值,那么结果等于Long.MIN_VALUE 的值。
3.如果参数为正⽆穷⼤或任何⼤于等于 Long.MAX_VALUE 的值,那么结果等于Long.MAX_VALUE 的值。
向下取整,即⼩于这个数的最⼤的那个整数。
向上取整,即⼤于这个数的最⼩的那个整数。
返回最接近该值的那个整数。
8. Java数组类型与泛型不⼀样,在运⾏时期类型会记住,可以⽤ComponentType()来获取数组实际类型。如果要通过反射构造⼀个数组类型的对象的话,需要使⽤flect.Array类:
public static Object newInstance(Class<?> componentType, int length)
throws NegativeArraySizeException {
return newArray(componentType, length);
}
在java中进⾏数组拷贝只有System.arraycopy()⽅法:
public static native void arraycopy(Object src,  int  srcPos,
Object dest, int destPos,
int length);
9.  java boolean不能强转为int,不能进⾏加减乘除操作,但是可以进⾏按位与或操作。java char 转 int 需调⽤Integer.parseInt()⽅法,如果直接调⽤char c = 'c', int i = c,得到的是变量c的ascll码值。char 在java中占⽤两个字节,可以进⾏加减乘除操作。
⼆、java IO
1. java io流分为两⼤类,⼀是stream流,顶层抽象类InputStream和OutpuStream。当使⽤FileOutpuStream类写⽂件时,底层⽤了open()⽅法,该⽅法会返回⼀个fd(⽂件描述符),⽂件描述符是内核为了⾼效管理已被打开的⽂件所创建的索引,⽤于指向被打开的⽂件,所有执⾏I/O操作的系统调⽤都通过⽂件描述符;⽂件描述符是⼀个简单的⾮负整数,⽤以表明每个被进程打开的⽂件。程序
刚刚启动时,第⼀个打开的⽂件是0,第⼆个是1,以此类推。也可以理解为⽂件的⾝份ID。同时还有⼀个⽂件偏移量,lseek,默认为0。Socket类的getOuputStream返回了SocketOutputStream,其实也是继承⼦FileOutpuStream类的。ByteArrayInputStream可以将⼀个byte数组转换为流式读取。如果需要缓冲的话,可以使⽤BufferInputStream,该类有⼀个byte buf[]成员变量,默认⼤⼩是8192。另⼀类是Reader类,如果⽂件要按⾏读取,需要使⽤BufferReader包裹FileReader类。
2. unicode和utf-8区别:
⽤通信理论的思路可以理解为:
unicode是信源编码,对字符集数字化;
utf8是信道编码,为更好的存储和传输。
3. java nio
Java IO和NIO之间第⼀个最⼤的区别是,IO是⾯向流的,NIO是⾯向缓冲区的。
缓冲区包括以下类型:
ByteBuffer
CharBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBuffer
其中只有ByteBuffer类直接对外部可见, 可以直接使⽤, 其他的类都需要ByteBuffer类的asxxx()⽅法, 要获得⼀个ByteBuffer对象, 只能使⽤该类的静态⽅法:
public static ByteBuffer allocateDirect(int capacity) {
return new DirectByteBuffer(capacity);
}
public static ByteBuffer allocate(int capacity) {
if (capacity < 0)
throw new IllegalArgumentException();
return new HeapByteBuffer(capacity, capacity);
}
public static ByteBuffer wrap(byte[] array,
int offset, int length)
{
try {
return new HeapByteBuffer(array, offset, length);
} catch (IllegalArgumentException x) {
throw new IndexOutOfBoundsException();
}
}
要往⼀个缓冲区⾥写⼊数据时, 需要先调⽤其clear()⽅法, ⽅法代码如下:
public final Buffer clear() {
position = 0;
limit = capacity;
mark = -1;
return this;
}
⽽要从缓冲区⾥读数据时,需要先调⽤flip⽅法, ⽅法代码如下:
public final Buffer flip() {
limit = position;
position = 0;
mark = -1;
return this;
}
compact()⽅法将position和limit之间的数据复制到缓冲区的开始位置, 为后续的put()⽅法调⽤让出空间.代码如下:
public ByteBuffer compact() {
System.arraycopy(hb, ix(position()), hb, ix(0), remaining());
position(remaining());
limit(capacity());
discardMark();
return this;
}
三、java Exception
Java对异常进⾏了分类,不同类型的异常分别⽤不同的Java类表⽰,所有异常的根类为 java.lang.Throwable,Throwable下⾯⼜派⽣了两个⼦类:Error和Exception。
Error表⽰应⽤程序本⾝⽆法克服和恢复的⼀种严重问题。
Exception表⽰程序还能够克服和恢复的问题,其中⼜分为系统异常和普通异常。
系统异常是软件本⾝缺陷所导致的问题,也就是软件开发⼈员考虑不周所导致的问题,软件使⽤者⽆法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运⾏或者让软件死掉,例如,数组下标越界(ArrayIndexOutOfBoundsException),空指针异常(NullPointerException)、类转换异常(ClassCastException)。
普通异常是运⾏环境的变化或异常所导致的问题,是⽤户能够克服的问题,例如,⽹络断线,硬盘空间不够,发⽣这样的异常后,程序不应该死掉。
Java为系统异常和普通异常提供了不同的解决⽅案,编译器强制普通异常必须atch处理或⽤throws声明继续抛给上层调⽤⽅法处理,所以普通异常也称为checked异常,⽽系统异常可以处理也可以不处理,所以编译器不强制⽤atch处理或⽤throws声明,所以系统异常也称为unchecked异常。
⼀个throwable包含它创建时线程执⾏堆栈的快照。 它还可以包含⼀个消息字符串,该字符串提供有关该错误的更多信息。 随着时间的推移,throwable可以抑制其他throwables的传播。 最后,throwable还可以包含⼀个 cause 原因:另⼀个throwable导致了该throwable 的构造。 此因果信息的记录称为链接异常 ⼯具,因为原因本⾝可以有原因,依此类推,导致异常的“链”,每个异常都是由另⼀个原因引起的 。
四、java 集合框架
1. 集合框架分为两⼤类Collection和Map。Collection接⼝继承了Iterable接⼝。
2.Iterator与Iterable
iterator为Java中的迭代器对象,是能够对List这样的集合进⾏迭代遍历的底层依赖。⽽iterable接⼝⾥定义了返回iterator的⽅法,相当于对iterator的封装,同时实现了iterable接⼝的类可以⽀持for each循环。
3. iterator内部细节
jdk中Iterator接⼝主要⽅法如下: