Java-自学笔记

Java是一种纯面向对象的语言,具有跨平台,健壮性强,较高的安全性(自动回收垃圾,强制类型检查,取消指针)。

第一步:编写程序(.java文件)->第二步:编译程序,通过编译器生成(.class文件)->第三步:运行程序(JVM java运行平台)。

Java 文档注释

Java 支持三种注释方式。前两种分别是 // 和 /* */,第三种被称作说明注释,它以 /** 开始,以 */结束。

说明注释允许你在程序中嵌入关于程序的信息。你可以使用 javadoc 工具软件来生成信息,并输出到HTML文件中。

说明注释,使你更加方便的记录你的程序信息。

javadoc 标签

javadoc 工具软件识别以下标签:

标签

描述

示例

@author

标识一个类的作者

@author description

@deprecated

指名一个过期的类或成员

@deprecated description

{@docRoot}

指明当前文档根目录的路径

Directory Path

@exception

标志一个类抛出的异常

@exception exception-name explanation

{@inheritDoc}

从直接父类继承的注释

Inherits a comment from the immediate surperclass.

{@link}

插入一个到另一个主题的链接

{@link name text}

{@linkplain}

插入一个到另一个主题的链接,但是该链接显示纯文本字体

Inserts an in-line link to another topic.

@param

说明一个方法的参数

@param parameter-name explanation

@return

说明返回值类型

@return explanation

@see

指定一个到另一个主题的链接

@see anchor

@serial

说明一个序列化属性

@serial description

@serialData

说明通过writeObject( ) 和 writeExternal( )方法写的数据

@serialData description

@serialField

说明一个ObjectStreamField组件

@serialField name type description

@since

标记当引入一个特定的变化时

@since release

@throws

和 @exception标签一样.

The @throws tag has the same meaning as the @exception tag.

{@value}

显示常量的值,该常量必须是static属性。

Displays the value of a constant, which must be a static field.

@version

指定类的版本

@version info

两个数交换:

如:a = 3 ;b = 2;

常规: temp = a; a = b; b = temp;

面试题:如果不使用第三个变量如何实现:

方法一:使用表达式法:a = a + b - (b= a);

方法二:使用加法:a = a + b; b = a - b ; a = a - b ;

方法三:使用异或操作:a = a ^ b; b = a ^ b ;a = a ^ b; //此方法最快;但注意a与b不能相同;

方法的重写:

如果创建子类对象是使用默认的构造方法,那么父类的默认构造方法也会被调用,如果创建子类对象时会调用父类的默认构造方法;

 

当父类中没有无参构造方法时,子类必须显示的调用父类的带参构造方法,怎么调用?可以在子类中显示的使用super(...)调用父类调用父类的构造方法,只能出现在第一句。

面试题:overloading与overriding的区别?

overloading:方法的重载,发生在同一个类中,方法名相同,参数列表不同,返回值无关;

overriding:方法的重写,发生在子父类中,方法名相同,参数列表相同,返回值相同,子类的访问修饰符要大于或者等于父类的访问修饰符,子类的异常声明必须小于或者等于父类的异常声明。如果方法被private,static,final修饰,那么不能被重写。

 

super关键字:

super可以完成以下操作:

1、使用super调用父类中 的属性,可以从父类示例处获得信息。

2、使用super调用父类中的方法,可以委托父类对象帮助完成某件事情。

3、使用super调用父类中的构造方法(super(实参)形式),必须在子类构造方法的第一条语句,调用父类中相应的构造方法,若不显示的写出来,默认调用父类的无参构造方法,比如,super();

this表示当前对象;使用super表示调用父类的属性;

 

final关键字:

1、使用final关键字声明一个常量(修饰属性或者修饰局部变量(最终变量),也成常量。)

2、使用final关键字声明一个方法(该方法为最终方法,且只能被子类继承,但是不能被子类重写)

3、使用final关键字声明一个类(该类就转变为最终类,没有子类的类,final修饰的类无法被 继承。)

4、在方法参数中使用final,在该方法内部不能修改参数的值)

 

throw与throws关键字

throws关键字:主要在方法的声明上使用,表示方法中不处理异常件,而交给调用处处理,实际上对于java程序员来讲,如果没有加入任何异常处理,默认由JVM进行异常处理操作。

throw关键字:表示在程序中手动跑出一个异常,因为从异常的处理机制来看,所有的异常一旦产生之后,实际上抛出的就是一个异常类的实例化对象,那么此对象也可以由throw直接抛出。

1、throwable是异常类的基类,分为Error和Exception,在编程中我们关注Exception

2、Exception分为编译期异常(受捡)和运行期异常(非受检)

3、异常会导致程序中断,无法继续执行

4、在开发中,我们需要把可能出现异常的代码使用try语句块包裹起来

5、处理异常可以让程序保持运行状态

6、catch可以有多个,顺序为从子类到父类,范围大的异常后置,小的放在前面

 

异常处理语法规则:

第一、try语句不能单独存在,可以和catch、finally组成try...catch...finally 、 try...catch 、 try...finally三种结构,catch语句可以有一个或多个,finally语句最多一个,try,catch,finally三个关键字均不能单独使用。

第二、try、catch、finally三个代码块中变量的作用域分别独立而不能相互访问

第三、多个catch块的时候,java虚拟机会匹配其中一个异常类或其子类,就执行这个catch块,而不会再执行别的catch块。

 

代码块:

1、普通代码块,在方法中写的代码块,用于作用域的划分。

2、在构造块中,是在类中定义的代码块,在创建对象时被调用,优于构造方法执行。

3、在类中使用static声明的代码块称为静态代码块

在第一次使用的时候被调用(创建对象),只会执行一次,优于构造块执行

我们在项目开发中,通常会使用静态代码块来初始化只调用一次的数据。比如说:数据库配置信息

小结:重点会使用的顺序是静态代码块,普通代码块,同步代码块,构造代码块。

 

单例设计模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点;

1、构造方法私有化

2、声明一个本类对象

3、给外部提供一个静态方法获取对象实例

类型:

1、饿汉式:在类被加载后,对象被创建,到程序结束后释放

2、懒汉式:在第一次调用getInstance方法时,对象被创建,到程序结束后释放

项目中为什么要使用单例,单例有什么好处?

1、在设计一些工具类的时候(通常工具类,只有功能方法,没有属性;)

2、工具类可能会被频繁调用

目的是为了节省重复创建对象所带来的内存消耗,从而来提高效率;

能不能使用构造方法私有化+静态方法来代替单例?有,实现工具类,但占用内存时间较长。如Math

 

面试题:

Exception与RuntimeException:

Exception:受检异常,在编程期检查,在调用抛出这个异常的方法是,必须显示的使用try...catch...

RuntimeException:非受检异常,在运行期检查,在调用抛出这个异常的方法时,可以不用显示的使用try...catch...

在自定义异常时,根据实际的业务要求,来决定使用哪个作为父类

 

assert关键字,表示断言。

当程序执行到某个固定位置的时候,程序中的某个变量的取值肯定是预期的结果,那么这种操作可以使用断言完成。

测试人员使用。

 

面试题:String赋值方式

string s1 = new String ("java”);//请问这行代码创建了几个对象?

答:创建了两个对象,首先String ("java”)会检查堆常量池中是否有“java”这个字符串常量,如果没有会在常量池中创建。紧接着,new会在内存中申请一个地址空间,创建一个对象s1指向"java"。

Sting S2 = “java”;//请问这行代码创建了几个对象?

答:创建了一个对象,直接在堆常量池中创建字符串常量”java“;常量池中的变量会共享,重复利用。

在String的这两种赋值方式中,我们推荐使用第一种方式。String表示一个字符串,内部使用字符数组实现,不能被继承(最终类),值不可变。

四种赋值方式的区别:

在直接赋值字符串连接时,考虑编译器和运行期

如果在编译期时,值可以被确定,那么就使用已有的对象,否则会创建新的对象。

字符串相加操作:

1、多个常量相加没有性能问题,在编译期优化。

2、变量与常量相加,会产生多个垃圾对象。

面试题:StringBuffer和StringBuilder的区别

//StringBuffer目的是解决字符串相加是带来的性能问题(常量与变量),内部实现采用字符数组,默认数组的长度为16,超过数组大小时,动态扩充的算法是原来长度*2+2

//所以当我们预知要添加的数组长度时,建议使用带初始化容量的构造方法,来避免动态扩充的次数,从而提高效率。保证多线程安全的,会影响性能。jdk1.0就有。

//StringBuilder是线程不安全,新能高,适合在单线程中使用,这种情况占大多数,在jdk1.5后添加。

 

Lambda表达式:

Lambda允许把函数作为一个方法的参数(函数作为参数传递进方法中),或者把代码看成数据。Lambda表达式用于简化java中接口式的匿名内部类。被称为函数式接口的概念。函数式接口就是一个具有一个方法的普通接口。像这样的接口,可以被隐式转换为Lambda表达式。

 

字节流与字符流的区别:

在所有的流操作里,字节永远是最基础的,任何基于字节的操作都是正确的。无论你是文本文件还是二进制的文件。

如果确认流里面只有可打印的字符,包括英文的和各种国家的文字,也包括中文,那么可以考虑用字符流。

由于编码不同,多字节的字符可能占用多个字节。比如,GBK的汉字就占用2个字节,而UTF-8的汉字就占用3个字节,所以,字符流是根据指定的编码,将1个或多个字节转化为java里面的Unicode的字符,然后进行操作。

字符操作一般使用Writer,Reader等,字节操作一般都是InputStream,OutputStream以及各种包装类,比如,BufferedInputStream和BufferedOutputStream等。

总结:

    • 如果你确认你要处理的流是可打印的字符,那么使用字符流会看上去简单一点,如果不确认,那么字节流总是不会错的。
    • 如何选择使用字节流还是字符流:一般操作非文本文件时,使用字节流。操作文本文件时,建议使用字符流。
    • 文件字符操作流会自带缓存,默认大小为1024字节,在缓存满后,或手动刷新缓存,或关闭流时会把数据写入文件
    • 字符流的内部实现其实还是字节流。

 

mock对象:也称为伪对象,在测试中的利用mock对象来代替真实对象,方便测试的进行。

java的封装性:指的是将对象的状态信息隐藏在对象内部,不允许外部程序直接访问对象内部信息,通过该类提供的方法实现对内部信息的操作访问。

反射机制:在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性

Java-自学笔记

 

Java-自学笔记

  • 当数字和字符串相加时,+号并不是数学意义的加号,而是表示相拼接。。。。
  •  

初始化顺序:

1.先父类,后子类

2.先属性,后构造函数

3.先静态,后非静态

4.静态初始化块,静态变量这两个是属于同一级别的,是按代码写得顺序执行的!(先静态属性,后静态代码块???)

5.同一类型(非数据类型,指以上),按代码先后顺序

方法重写的前提: 必须要存在继承的关系。

 

  • 方法的重写: 子父类出了同名的函数,这个我们就称作为方法的重写。

什么是时候要使用方法的重写:父类的功能无法满足子类的需求时。

方法重写要注意的事项:

    1.方法重写时, 方法名与形参列表必须一致。

    2.方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。

    3.方法重写时,子类的返回值类型必须要小于或者 等于父类的返回值类型。

    4.方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。

            Exception(最坏)

            RuntimeException(小坏)

  • 方法的重载:在一个类中 存在两个或者两个 以上的同名函数,称作为方法重载。

方法重载的要求

    1. 函数名要一致。

    2. 形参列表不一致(形参的个数或形参 的类型不一致)

    3. 与返回值类型无关。

  •  abstract可以修饰方法和类,不能修饰属性。抽象方法没有方法体,即没有大括号{}

 

 

private

default

protected

public

同一个类中

同一个包中

 

子类中

 

 

全局范围内

 

 

 

( 1 )对于外部类而言,它也可以使用访问控制符修饰,但外部类只能有两种访问控制级别: public 和默认。因为外部类没有处于任何类的内部,也就没有其所在类的内部、所在类的子类两个范围,因此 private 和 protected 访问控制符对外部类没有意义。

( 2 )内部类的上一级程序单元是外部类,它具有 4 个作用域:同一个类( private )、同一个包( protected )和任何位置( public)。

( 3 ) 因为局部成员的作用域是所在方法,其他程序单元永远不可能访问另一个方法中的局部变量,所以所有的局部成员都不能使用访问控制修饰符修饰。

 

JAVA集合框架

Java-自学笔记

 

构造方法是一种特殊的方法,具有以下特点:

(1)构造方法的方法名必须与类名相同。

(2)构造方法没有返回类型,也不能定义为void,在方法名前面不声明方法类型。

(3)构造方法的主要作用是完成对象的初始化工作,它能够把定义对象时的参数传给对象的域。

(4)一个类可以定义多个构造方法,如果在定义类时没有定义构造方法,则编译系统会自动插入一个无参数的默认构造器,这个构造器不执行任何代码。

(5)构造方法可以重载,以参数的个数,类型,顺序。

 

抽象类

特点:

1.抽象类中可以构造方法

2.抽象类中可以存在普通属性,方法,静态属性和方法。

3.抽象类中可以存在抽象方法。

4.如果一个类中有一个抽象方法,那么当前类一定是抽象类;抽象类中不一定有抽象方法。

5.抽象类中的抽象方法,需要有子类实现,如果子类不实现,则子类也需要定义为抽象的。

接口

1.在接口中只有方法的声明,没有方法体。

2.在接口中只有常量,因为定义的变量,在编译的时候都会默认加上public static final 

3.在接口中的方法,永远都被public来修饰。

4.接口中没有构造方法,也不能实例化接口的对象。

5.接口可以实现多继承

6.接口中定义的方法都需要有实现类来实现,如果实现类不能实现接口中的所有方法

7.则实现类定义为抽象类。

 

Grepcode简介

经常需要查看某些第三方的源码,一直在用的一个网站,功能比较简介、好用。  http://grepcode.com/

这是一个面向于java开发人员的网站,在这里你可以通过java的projects、classes等各种关键字在线查看它对应的源码,知道对应的project、classes等信息。 更方便的是,能提供非常多不同版本的源码在线查看、jar包、源码jar包、doc的下载。

Java-自学笔记

 

装饰者模式:

意图:动态的给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更为灵活。该模式以对客户端透明的方式扩展对象的功能。

使用环境:在不影响其他对象的情况下,以动态的方式给单个对象添加职责。处理那些可以撤销的职责。

当不能采用生成子类的方法进行扩充时,一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈现爆炸式增长,另一种情况可能是因为类定义被隐藏,或者类定义不能用于生成子类。

 

常见的字符编码:ISO8859-1、GBK/GB2312、unicode\UTF

ISO8859-1:编码属于单字节编码,最多只能表示0-255的字符范围,只要用在英文上面。

BGK/GB2313:中文的国际编码,专门用来表示汉字,是双字节编码。

unicode:java中使用此编码方式,也是最标准的一种编码,是使用16进制表示的编码。但此编码不兼容iso8859-1编码。

UTF:由于unicode不支持ISO8859-1编码,而且容易占用更多的空间,对于英文字母也需要两个字节编码,这样使用Unicode不便于传输和储存,因此产生了UTF编码。UTF编码兼容了ISO8859-1编码,也可以用来表示所有语言字符。不过UTF是不定长编码,每个字符的长度从1-6个字节不等,一般在中文网页中使用此编码,因为这样可以节省空间。

造成乱码的根本原因:

1、程序使用的编码与本机的编码不统一。

2、在网络中,客户端与服务器端编码不统一。(在web开发中出现的频率较多)··

 

New IO:

1、为什么要使用NIO?

NIO是JDK1.4加入的新包,NIO的创建目的是为了让java程序员可以实现告诉的I/O而无需编写自定义的本机代码,NIO将最耗时的I/O操作(即填充和提取缓冲区)转移回操作系统,因而可以极大的提高速度。

流与块的比较:

原来的I/O库(在java.io.*中)与NIO最重要的区别是数据打包和传输和传输的方式,原来的I/O以流的方式处理数据,而NIO以块的方式处理数据。

面向流的I/O 系统一次一个字节的处理数据,一个输入流产生一个字节的数据,一个输出流消费一个字节的数据。不利的一面是:面向流的I/O通常相当慢。

一个面向块的I/O系统以块的形式处理数据。每一个操作都在一步中产生或者消费一个数据块。按块处理数据比按流的字节处理数据要快得多,但是面向快的I/O 缺少一些面向流的I/O所具有的优雅型和简单性。

缓冲区:

在NIO库中,所以的数据都是用缓冲区处理的。在读数据时,它是直接读到缓冲区中的,在写数据时,它是写入到缓冲区中的,任何时候访问NIO中的数据,都是将它放到缓冲区中。

缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不仅仅是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。

缓冲区类型:

最常用的缓冲区类型是ByteBuffer,一个ByteBuffer可以在其底层字节数组上进行get/set操作(即字节的获取和设置)。ByteBuffer不是NIO中唯一的缓冲区类型。事实上,对于每一种基本java类型都有一种缓冲区类型。

ByteBuffer CharBuffer ShortBuffer intBuffer LongBuffer FloatBuffer DoubleBuffer

Channal:

Channal是一个对象,可以通过它读取和写入数据。拿NIO与原来的I/O做个比较,通道就像是流。正如前面提到的,所有的数据都通过Buffer对象来处理。永远不会将字节直接写入通道中,相反,是将数据写入包含一个或者多个字节的缓冲区。同样,不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。

 

比较IO操作的性能:

1、内存映射最快

2、NIO读写文件

3、使用了缓冲的流

4、无缓冲的IO流

 

Collection接口:集合框架ArrayList 与 Vector:

ArrayList:

1、实现原理:采用动态对象数组实现,默认构造方法创建了一个空数组。

2、第一次添加元素,扩展容量为10,之后的扩充算法:原来数组大小 + 原来数组的一半。

3、不适合进行删除或插入操作

4、为了防止数组动态扩充次数过多,建议创建ArrayList时,给定初始容量。

5、线程不安全,适合在单线程访问时使用。

 

Vector:

1、实现原理:采用动态对象数组实现,默认构造方法创建了一个大小为10的对象数组

2、扩充的算法:当增量为为0 时,扩充为原来大小的2倍,当增量大于0 时,扩充为原来大小 + 增量。

3、不适合删除或插入操作。

4、为了防止数组动态扩充次数过多,建议创建Vector时,给定初始容量。

5、线程安全,适合在多线程访问时使用,在单线程下使用效率较低。

List接口:

LinkedList:

1、实现原理:采用双向链表结构实现

2、适合插入,删除操作,性能高

 

set接口:

1、无序的(不保证顺序)

2、不允许重复的元素

HashSet :基于哈希表(HashMap)实现,不允许重复,可以有一个NULL元素,不保证顺序恒久不变。添加元素时把元素作为HashMap的key存储,HashMap的value使用一个固定的object对象,排除重复元素时通过equals来检查对象是否相同,判断两个对象是否相同,先判断两个对象的hashCode是否相同(如果两个对象的hashCode相同,不一定是同一个对象,如果不同,那一定不是同一个对象),如果不同,则两个对象不是同一个对象,如果相同,还要进行equals判断,equals相同则是同一个对象,不同则不是同一个对象。如果自定义对象要认为属性值群相同时为同一个对象,那么我们要重写对象所在类的hashCode和equals方法。

TreeSet :有序的,基于TreeMap(二叉树数据结构),对象需要比较大小,通过对象比较器来实现,对象比较器还可以用来去除重复元素,如果自定义的数据类,没有实现比较器接口,将无法添加到TreeSet集合中。

LinkedHashSet : 哈希表和链接列表实现,维护着一个运行与所有条目的双重链接列表,此链接列表定义了迭代顺序,即按照将元素插入到set中的顺序(插入顺序)进行迭代。

  • 如果要排序,选择treeSet
  • 如果不要排序,也不用保证顺序选择HashSet
  • 不要排序,要保证顺序,选择LinkedHashSet

 

集合框架Iterator接口:

很多情况下我们需要把集合的内容进行输出,也就是遍历集合,遍历集合的方式有以下几种:

1、Iterator(使用率最高)

2、ListIterator

3、Enumeration

4、foreach

 

集合框架Map接口:

public interface Map<K , V>

将键映射到值的对象,一个映射不能包含重复的键,每个键最多只能映射到一个值

Map接口

* 1、键值对 存储一组对象

* 2、Key不能重复(唯一),Value可以重复

* 3、具体的实现类:HashMap TreeMap HashTable LinkedHashMap

HashMap的实现原理

1、基于哈希表(数组 + 链表 + 二叉树(红黑树))

2、默认加载因子为0.75(75%的空间存了值,表示数组空间已经达到高峰了,要扩充重新散列)默认数组大小是16

3、如何把对象存储到Hash表中:把Key对象通过hash()方法计算hash值,然后用这个hash值对数组长度取余数(默认16),来决定Key对象在数组中的存储的位置,当这个位置有多个对象时,以链表结构存储 ,JDK1.8后,当链表长度大于8时,链表将转换为红黑树结构存储。

这样做的目的是为了取值更快,存储的数据量越大,性能的表现越明显。

4、扩充原理:当数组的容量超过了75%,那么表示该数组需要扩充。扩充方法:当前数组容量 << 1,相对于是乘以2,扩大一倍。然后所有对象全部重新执行上面的第三步重新散列,此过程极度消耗性能。为了避免扩充次数过多,在开发过程中可以修改默认值大小。

5、线程不安全,适合在单线程中使用。

Hashtable

  1. 基于哈希表实现(数组+链表)
  2. 默认数组大小为11,加载因子0,75
  3. 扩充方式:原数组大小<<1(*2)+1
  4. 线程安全的,用在多线程访问。

LinkedHashMap:

LinkedHashMap是HashMap的子类,由于HashMap不能保证顺序恒久不变,此类使用一个双重链表来维护元素添加顺序。

 

TreeMap:

基于红黑树的NavigableMap实现,该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的Comparable进行排序,具体取决于使用的构造方法。

 

迭代器模式的角色构成:

1、迭代器角色(Iterator):定义遍历元素所需的方法,一般来说会有三个方法:取得下一个元素的方法next(),判断是否遍历结束的方法hasNext(),移除当前对象的方法remove()

2、具体迭代器角色(Concrete Iterator),实现迭代器接口中定义的方法,完成集合的迭代。

3、容器角色(Aggregate):一般是一个接口,提供一个Iterator()方法,例如java中的Collection接口,List接口,Set接口等。

4、具体容器角色(ConcreteAggregate),就是抽象容器的具体实现类。比如List接口的有序列表实现ArrayList。List接口的链表实现LinkList,Set接口的哈希列表的实现HashSet等。

 

guava对集合的支持:下载地址:http://central.maven.org/maven2/com/google/guava/guava/

https://opensource.google.com/projects/guava

Guava工程包含了若干倍Google的java项目广泛依赖的核心库,例如,结合【collections】、缓存【caching】、原生类型支持【primitive support】、并发库【concurrency libraries】、通用注解【common annotation】、字符串处理【string processing】、I/O等等。

1、不可变集合:用不变的集合进行防御性编程和性能提升。

2、新集合类型:multisets multimaps,tables等

3、强大的集合工具类,提供java.util.Collections中没有的集合工具

4、扩展工具类:让实现和扩展集合类变得更容易,比如创建Collection的装饰器,或实现迭代器。

 

 

守护线程与yield:

public final void setDaemon(boolean on)

将此线程标记为daemon线程或者用户线程,当运行的唯一线程都是守护进程线程时,java虚拟机将退出。

线程同步:

1、多线程共享数据

在多线程的操作中,多个线程有可能同时处理同一个资源,这就是多线程中的资源共享。

2、线程同步

解决数据共享问题,必须使用同步,所谓同步就是指多个线程在同一个时间段内只能有一个线程执行指定代码,其他线程要等待此线程完成之后才可以继续执行。

线程同步,有以下三种方法:

(1)同步代码块:

synchronized(要同步的对象){

要同步的操作;}

(2)同步方法:

public synchronized void method(){

要同步的操作;

}

(3)Lock (ReentrantLock)更灵活的代码控制

3、同步准则:

当编写synchronized块时,有几个简单的准则可以遵循,这些准则在避免死锁和性能危险的风险方面大有帮助:

(1)使代码块保持简短,把不随线程变化的预处理和后处理移出synchronized块。

(2)不要阻塞。如InputStream.read()

(3)在持有锁的时候,不要对其他对象调用方法;

 

生产者-消费者:

两个线程协同工作:先生产,后消费

面试题:sleep与wait的区别:

sleep:让线程进入休眠状态,让出CPU的时间片,不释放对象监视器的所有权(对象锁)。

wait:让线程进入等待状态,让出CPU的时间片,并释放对象监视器的所有权,等待其他线程通过notify方法来唤醒。(在同步方法 中使用)

一个简洁易用的基于TCP/IP通信的JAVA框架:MINA框架:http://mina.apache.org/downloads-mina.html

开发一个MINA应用,简单的说就是:创建连接,设定过滤规则,编写自己的消息处理器。

Apache MINA是一个网络应用程序框架,可帮助用户轻松开发高性能和高可扩展性的网络应用程序。它通过Java NIO在各种传输(如TCP / IP和UDP / IP)上提供抽象的事件驱动异步API。

Apache MINA经常被称为:

  • NIO框架库,
  • 客户端服务器框架库,或
  • 网络套接字库

Apache MINA附带了许多子项目:

  • Asyncweb:构建在MINA异步框架之上的HTTP服务器
  • FtpServer:FTP服务器
  • SSHd:支持SSH协议的Java库
  • Vysper:XMPP服务器

用户手册:http://mina.apache.org/mina-project/userguide/user-guide-toc.html

反射与内省:

Class类是一切反射的根源

得到Class类的对象有三种方法:

第一种形式:Object类中的getClass()方法

第二种形式:类.class

第三种形式:通过Class类的forName方法

动态代理

所谓动态代理,即通过代理类,Proxy的代理,接口和实现类之间可以不直接发生联系,而可以在运行期(Runtime)实现动态关联。

java动态代理主要是使用java.lang.reflect包中的两个类。InvocaHandler类,proxy类

代理模式(proxy):为其他对象提供一种代理以控制对这个对象的访问。代理模式说白了就是“真实对象”的代表。在访问对象时引入一定程度的间接性,因为这种间接性可以附加多种用途。

类加载器的原理分析:

1、类加载器过程:JVM将类加载过程分为三个步骤,装载(load),链接(link)和初始化(Initialize)链接又分为三个步骤。

1)转载:查找并加载类的二进制数据;

2)链接

验证:确保被加载类的正确性;

准备:为类的静态变量分配内存,并将其初始化为默认值;

解析:把类中的符号引用转换为直接引用;

3)初始化:为类的静态变量赋予正确的初始值;

2、类的初始化,类什么时候才被初始化

1)创建类的示例,也就是new一个对象

2)访问某个类或接口的静态变量,或者对该静态变量赋值

3)调用类的静态方法

4)反射(Class.forName())

5)初始化一个类的子类(会首先初始化子类的父类)

6)JVM启动时标明的启动类,即文件名和类名相同的那个类

3、类的加载

指的是将类的class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区内,然后在堆区创建一个这个类的java.lang.Class对象,用来封装类在方法区类的对象。

JavaBean的概念:

Bean理解为组件的意思,JavaBean就是Java组件,在广泛的理解就是一个类,对于组件来说,关键在于要具有:“能够被IDE构建工具侦测其属性和事件”的能力,通常在java中。

一个javaBean要具备这样的命名规则:

1、对于一个名称为xxx的属性,通常你要写两个方法:getXxx()和setXxx()。任何浏览这些方法的工具,都会把get和set后面的第一个字母自动转换为小写字母。即得到属性

2、对于布尔型属性,可以使用以上get和set方式,也可以把get替换成is。

3、Bean的普通方法不必遵循以上的命名规则,不过他们必须是public的。

4、对于事件,要使用Swing中处理监听器的方式,如addWindowListenner , removeWindowListenner ;

BeanUtils工具类:http://commons.apache.org/proper/commons-beanutils/

内省(Introspector):是java语言对Bean类属性、事件的一种缺省处理方法,例如类A中有属性name,那么我们可以通过getName,setName来得到其值或者设置新的值。通过getName/setName来访问name属性,这就是默认的规则。

理解可配置的AOP框架:

1、AOP的概念:Aspect Oriented Programming (面向切面编程)核心就是使用代理模式

2、可配置AOP框架实现

AOP使用场景:AOP用来封装横切关注点,具体可以在这些场景中使用:权限、缓存、错误处理、调试、记录跟踪、持久化、同步、事务。。。。

volatile关键字:

volatile提醒编译器它后面所定义的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,都会直接从变量地址中读取数据,如果没有volatile关键字,则编译器可能优化读取和存储,可能暂时使用寄存器中的值,如果这个变量由别的程序更新了的话,将出现不一致的现象。

SAX解析XML的特点:

1、基于事件驱动

2、顺序读取,速度快

3、不能任意读取节点(灵活性差)

4、解析时占用的内存小

5、SAX更适用于在性能要求更高的设备上使用(Android开发中)

DOM解析XML:

java解析XML通常有两种方式:DOM和SAX

DOM:Document Object Model (文档对象模型)

DOM的特性:

定义一组java接口,基于对象,与语言和平台无关将XML文档表示为树,在内存中解析和存储XML文档,允许随机访问文档的不同部分。

DOM解析XML的优点:由于树在内存中是持久的,因此可以修改后更新,它还可以在任何时候在树中上下导航,API使用起来也较为简单。

1、基于树形结构,通过解析器一次性把文档加载到内存中,所以会比较占用内存,可以随机访问。更加灵活适合在web开发中使用。

JDOM解析XML:

JDOM简化了与XML的交互并且比使用DOM实现更快,JDOM与DOM主要有两方面不同。

1、JDOM仅使用具体类而不使用接口,这在某方面简化了API,但是也限制了灵活性。

2、API大量使用了Collections类,简化了那些已经熟悉这些类的java开发者的使用。

下载地址:http://www.jdom.org/

(1)与DOM类似基于树形结构

(2)与DOM的区别:使用第三方开源组件,实现使用java的Collections

DOM4J解析XML:

DOM4J是一个非常优秀的java XML API,具有性能优异、功能强大和极端易用使用的特点,同时它也是一个开源代码的软件,可以在SourceForge上找到它。在对主流的javaXML API 进行的性能、功能和易用性的评测,DOM4J无论在哪个方面都是非常出色的。

如今你可以看到越来越多的java软件都在使用DOM4J来读写XML,特别值得一提的是:连Sun的JAXM也在用DOM4J。这是必须使用的jar包。Hibeinate用它来读写配置文件。

下载地址:http://dom4j.github.io

1、基于树形结构,第三方组件

2、解析速度快,效率更高,使用的java中的迭代器实现数据读取,在web框架中使用较多(Hibernate)

实现XML转换的工具包:xpp3_min-1.1.4c,jar 和 xstream.1.4.2.jar

 

JSON(javaScript Object Notation)是一种轻量级的数据交换格式

JSON数据格式的特点:

JSON建构于两种结构:

1、“名称/值”对的集合

2、值的有序列表(数组)

JSON表示名称/值对的方式:{“firstName”:“Vincent”,“lastName":"ma","email":"[email protected]"}

表示数组:

{"user":[{“firstName”:“Vincent”,“lastName":"ma","email":"[email protected]"},{“firstName”:“Vin”,“lastName":"da","email":"[email protected]"}] }

GSON是Google 开发的java API,用于转换java对象和JSON对象。

下载地址:http://www.mvnreposition.com/artifact/com.google.code.gson/gson

XML与JSON的比较:

1、JSON和XML的数据可读性基本相同;

2、JSON和XML同样拥有丰富的解析手段;

3、JSON相对于XML来说,数据的体积更小;

4、JSON与javaScript的交互更加方便;

5、JSON对数据的描述性比XML较差;

6、JSON的速度要远远快于XML;

适合的场景:

(1)数据传输:JSON要比XML更有优势;

(2)存储数据:XML描述性更强;

(3)XML通常用作配置文件;

 

接口回调:

当一个对象需要给外部对象提供数据时,我们可以定义一个内部接口把数据通过接口传递出去,所有外部对象需要这个数据时,就实现这个接口,这样的好处是传递数据的对象不直接依赖接收数据的对象(降低耦合)

项目中使用的技术点:

1、XML解析

xStream组件,dom4j组件

2、文件对象流输入输出

3、自定义异常

4、分层概念:view->service->dao(data access object)

5、设计模式:单例、工厂

6、集合

7、读取properties

8、UML时序图

9、Git