final
1.修饰类 表示该类不能被继承
2.修饰方法 表示该方法不能被重写
3.修饰基本类型变量 表示该变量只能被赋值一次,如果修饰引用,那么表示引用不可变,引用指向的内容可变。
4.被final修饰的方法,JVM会尝试将其内联,以提高运行效率
5.被final修饰的常量,在编译阶段会存入常量池中。
finally
finally 是用于异常处理的场面,无论是否有异常抛出,都会执行
finalize
finalize是Object的方法,所有类都继承了该方法。 当一个对象满足垃圾回收的条件,并且被回收的时候,其finalize()方法就会被调用
祖先java.lang包中的 Throwable类。Throwable: 有两个重要的子类:Exception(异常) 和 Error(错误) ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。
1.Error(错误):是程序无法处理的错误,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVM(Java 虚拟机)出现的问题。例如,
Java虚拟机运行错误(Virtual MachineError),当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时,Java虚拟机(JVM)一般会选择线程终止。
2.Exception(异常):是程序本身可以处理的异常。 Exception 类有一个重要的子类 RuntimeException。RuntimeException 异常由Java虚拟机抛出。NullPointerException
(要访问的变量没有引用任何对象时,抛出该异常)、ArithmeticException(算术运算异常,一个整数除以0时,抛出该异常)和 ArrayIndexOutOfBoundsException (下标越界异常)。
3.Throwable类常用方法
1. public string getMessage():返回异常发生时的详细信息
2. public string toString():返回异常发生时的简要描述
3. public void printStackTrace():在控制台上打印Throwable对象封装的异常信息
4.异常处理总结
try 块: 用于捕获异常。其后可接零个或多个catch块,如果没有catch块,则必须跟一个finally块。
catch 块:用于处理try捕获到的异常。
finally 块: 无论是否捕获或处理异常,finally块里的语句都会被执行。当在try块或catch块中遇到return语句时,finally语句块将在方法返回之前被执行
5.在以下4种特殊情况下,finally块不会被执行:
1.在finally语句块中发生了异常。
2.在前面的代码中用了System.exit()退出程序。
3.程序所在的线程死亡。
4.关闭CPU。
1.NullPointerException (空指针异常)
2.ArrayIndexOutOfBoundsException(数组下标越界)
3.IllegalArgumentException (参数错误)
4.ArithmeticException 算术异常,比如除数为零
5.ClassCastException 类型转换异常
error
1.OutOfMemoryError (堆内存溢出)
2. StackOverflowError(栈内存溢出)
Java中所有的流都是基于字节流,所以最基本的流是 字节流
1.输入输出字节流
InputStream OutputStream
2.字符流
在字节流的基础上,封装了字符流
Reader Writer
3.缓存流
进一步,又封装了缓存流
BufferedReader PrintWriter
4.数据流
DataInputStream DataOutputStream
5.对象流
ObjectInputStream ObjectOutputStream
方法1:通过 Scanner
Scanner input = new Scanner(System.in); String s = input.nextLine(); input.close();
Scanner input = new Scanner(System.in);
String s = input.nextLine();
input.close();
方法2:通过 BufferedReader
BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
String s = input.readLine();
1.java反射是什么
编译期和运行期,编译期就是编译器帮你把源代码翻译成机器能识别的代码,比如编译器把java代码编译成jvm识别的字节码文件,而运行期指的是将可执行文件交给操作系统去执行,JAVA反射机制是在运行状态中,
对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制
2. java反射(Reflection)的底层实现原理
Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:其中getClass()返回一个Class 对象
而这个Class 类十分特殊。它和一般类一样继承自Object,当一个class被加载,或当加载器(class loader)的defineClass()被JVM调用,JVM 便自动产生一个Class 对象。
这边列了下Class类其中的方法
获取公共构造器 getConstructors()
获取所有构造器 getDeclaredConstructors()
获取该类对象 newInstance()
获取类名包含包路径 getName()
获取类名不包含包路径 getSimpleName()
获取类公共类型的所有属性 getFields()
获取类的所有属性 getDeclaredFields()
获取类公共类型的指定属性 getField(String name)
获取类全部类型的指定属性 getDeclaredField(String name)
获取类公共类型的方法 getMethods()
获取类的所有方法 getDeclaredMethods()
获得类的特定公共类型方法: getMethod(String name, Class[] parameterTypes)
获取内部类 getDeclaredClasses()
获取外部类 getDeclaringClass()
获取修饰符 getModifiers()
获取所在包 getPackage()
获取所实现的接口 getInterfaces()
3.创建反射实例的三种方式
1.直接通过类名点.class获取
2.通过Object类的getClass方法来获取 通过Object类的getClass方法来获取
3.通过全类名获取用的比较多推荐使用 例如:Class.forName(“com.mysql.jdbc.Driver”);
https://blog.csdn.net/sinat_38259539/article/details/71799078 关于反射
java中class.forName()和classLoader都可用来对类进行加载。
class.forName()前者除了将类的.class文件加载到jvm中之外,还会对类进行解释,执行类中的static块。
而classLoader只干一件事情,就是将.class文件加载到jvm中,不会执行static中的内容,只有在newInstance才会去执行static块。
1. 序列化是干什么的?
简单说就是将内存中的对象保存下来,并且可以把保存的对象状态再读出来。
实现java序列化的手段是让该类实现接口 Serializable,这个接口是一个标识性接口,没有任何方法,仅仅用于表示该类可以序列化。
2. 什么情况下需要序列化
当你想把的内存中的对象保存到一个文件中或者数据库中时候;
当你想用序列化在网络上传送对象的时候;
当你想通过RMI传输对象的时候;
3.**相关注意事项 **
当一个父类实现序列化,子类自动实现序列化,不需要显式实现Serializable接口;
把一个对象完全转成字节序列,方便传输。
就像你寄一箱饼干,因为体积太大,就全压成粉末紧紧地一包寄出去,这就是序列化的作用。
只不过JAVA的序列化是可以完全还原的。
对于不想进行序列化的变量,使用transient关键字修饰。
transient关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复。transient只能修饰变量,不能修饰类和方法。
浅拷贝与深拷贝
看了很多文章,有些说浅拷贝只是拷贝引用地址,深拷贝才拷贝具体应用的对象,但经过LZ的核实发现有些文章个人感觉对拷贝的理解不是很正确。
总结了一下
浅拷贝
只复制一个对象,对象内部存在的指向其他对象数组或者引用则不复制
深拷贝
深拷贝:对象,对象内部的引用均复制
拷贝的几种方法
System.arraycopy(浅拷贝)
Arrays.copyOf(浅拷贝)
实际上它调用的就是System.arraycopy.
Object.clone
clone()比较特殊,对于对象而言,它是深拷贝,但是对于数组而言,它是浅拷贝。
在Java Web程序中,Servlet主要负责接收用户请求HttpServletRequest,在doGet(),doPost()中做相应的处理,并将回应HttpServletResponse反馈给用户。Servlet可以设置初始化参数,供Servlet内部使用。
一个Servlet类只会有一个实例,在它初始化时调用init()方法,销毁时调用destroy()方法。Servlet需要在web.xml中配置(MyEclipse中创建Servlet会自动配置),一个Servlet可以设置多个URL访问。
Servlet不是线程安全,因此要谨慎使用类变量。
1.需要为每个请求启动一个操作CGI程序的系统进程。如果请求频繁,这将会带来很大的开销。
2.需要为每个请求加载和运行一个CGI程序,这将带来很大的开销。
3.需要重复编写处理网络协议的代码以及编码,这些工作都是非常耗时的。
1.只需要启动一个操作系统进程以及加载一个JVM,大大降低了系统的开销。
2.如果多个请求需要做同样处理的时候,这时候只需要加载一个类,这也大大降低了开销。
3.所有动态加载的类可以实现对网络协议以及请求解码的共享,大大降低了工作量。
4.Servlet能直接和Web服务器交互,而普通的CGI程序不能。Servlet还能在各个程序之间共享数据,使数据库连接池之类的功能很容易实现。
补充: Sun Microsystems公司在1996年发布Servlet技术就是为了和CGI进行竞争,Servlet是一个特殊的Java程序,一个基于Java的Web应用通常包含一个或多个Servlet类。
Servlet不能够自行创建并执行,它是在Servlet容器中运行的,容器将用户的请求传递给Servlet程序,并将Servlet的响应回传给用户。通常一个Servlet会关联一个或多个JSP页面。
以前CGI经常因为性能开销上的问题被诟病,然而Fast CGI早就已经解决了CGI效率上的问题,所以面试的时候大可不必信口开河的诟病CGI,事实上有很多你熟悉的网站都使用了CGI技术
Servlet接口定义了5个方法,其中前三个方法与Servlet生命周期相关:
1.void init(ServletConfig config) throws ServletException
2.void service(ServletRequest req, ServletResponse resp) throws ServletException, java.io.IOException
3.void destory()
4.java.lang.String getServletInfo()
5.ServletConfig getServletConfig()
生命周期(重要):
一个Servlet的生命周期由 实例化,初始化,提供服务,销毁,被回收 几个步骤组成

Web容器加载Servlet并将其实例化后,Servlet生命周期开始,容器运行其init()方法进行Servlet的初始化;请求到达时调用Servlet的service()方法,
service()方法会根据需要调用与请求对应的doGet或doPost等方法;当服务器关闭或项目被卸载时服务器会将Servlet实例销毁,此时会调用Servlet的destroy()方法。
init方法和destory方法只会执行一次,service方法客户端每次请求Servlet都会执行。Servlet中有时会用到一些需要初始化与销毁的资源,因此可以把初始化资源的代码放入init方法中,
销毁资源的代码放入destroy方法中,这样就不需要每次处理客户端的请求都要初始化与销毁资源。
①get请求用来从服务器上获得资源,而post是用来向服务器提交数据;
②get将表单中数据按照name=value的形式,添加到action 所指向的URL 后面,并且两者使用"?“连接,而各个变量之间使用”&"连接;post是将表单中的数据放在HTTP协议的请求头或消息体中,
传递到action所指向URL;
③get传输的数据要受到URL长度限制(1024字节即256个字符);而post可以传输大量的数据,上传文件通常要使用post方式;
④使用get时参数会显示在地址栏上,如果这些数据不是敏感数据,那么可以使用get;对于敏感数据还是应用使用post;
⑤get使用MIME类型application/x-www-form-urlencoded的URL编码(也叫百分号编码)文本的格式传递参数,保证被传送的参数由遵循规范的文本组成,例如一个空格的编码是"%20"。
补充:GET方式提交表单的典型应用是搜索引擎。GET方式就是被设计为查询用的。
转发是服务器行为,重定向是客户端行为。
转发(Forword) 通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServletResponse response)方法实现的。
RequestDispatcher可以通过HttpServletRequest 的getRequestDispatcher()方法获得。
例如下面的代码就是跳转到login_success.jsp页面。
request.getRequestDispatcher("login_success.jsp").forward(request, response);
重定向(Redirect) 是利用服务器返回的状态吗来实现的。客户端浏览器请求服务器的时候,服务器会返回一个状态码。服务器通过HttpServletRequestResponse的setStatus(int status)方法设置状态码。
如果服务器返回301或者302,则浏览器会到新的网址重新请求该资源。
1.从地址栏显示来说
forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,
所以它的地址栏还是原来的地址. redirect是服务端根据逻辑,发送一个状态码,告诉浏览器重新去请求那个地址.所以地址栏显示的是新的URL.
2.从数据共享来说
forward:转发页面和转发到的页面可以共享request里面的数据. redirect:不能共享数据.
3.从运用地方来说
forward:一般用于用户登陆的时候,根据角色转发到相应的模块. redirect:一般用于用户注销登陆时返回主页面和跳转到其它的网站等
4.从效率来说
forward:高. redirect:低.
Servlet不是线程安全的,多线程并发的读写会导致数据不同步的问题。 解决的办法是尽量不要定义name属性,而是要把name变量分别定义在doGet()和doPost()方法内。
虽然使用synchronized(name){}语句块可以解决问题,但是会造成线程的等待,不是很科学的办法。 注意:多线程的并发的读写Servlet类属性会导致数据不同步。
但是如果只是并发地读取属性而不写入,则不存在数据不同步的问题。因此Servlet里的只读属性最好定义为final类型的。
其实这个问题在上面已经阐述过了,Servlet是一个特殊的Java程序, 它运行于服务器的JVM中,能够依靠服务器的支持向浏览器提供显示内容。
JSP本质上是Servlet的一种简易形式,JSP会被服务器处理成一个类似于Servlet的Java程序,可以简化页面内容的生成。Servlet和JSP最主要的不同点在于,
Servlet的应用逻辑是在Java文件中,并且完全从表示层中的HTML分离开来。而JSP的情况是Java和HTML可以组合成一个扩展名为.jsp的文件。有人说,Servlet就是在Java中写HTML,
而JSP就是在HTML中写Java代码,当然这个说法是很片面且不够准确的。JSP侧重于视图,Servlet更侧重于控制逻辑,在MVC架构模式中,
JSP适合充当视图(view)而Servlet适合充当控制器(controller)。
JSP有9个内置对象:
1.request:封装客户端的请求,其中包含来自GET或POST请求的参数;
2.response:封装服务器对客户端的响应;
3.pageContext:通过该对象可以获取其他对象;
4.session:封装用户会话的对象;
5.application:封装服务器运行环境的对象;
6.out:输出服务器响应的输出流对象;
7.config:Web应用的配置对象;
8.page:JSP页面本身(相当于Java程序中的this);
9.exception:封装页面抛出异常的对象。
JSP中的四种作用域包括page、request、session和application,具体来说:
1.page代表与一个页面相关的对象和属性。
2.request代表与Web客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个Web组件;需要在页面显示的临时数据可以置于此作用域。
3.session代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户相关的数据应该放在用户自己的session中。
4.application代表与整个Web应用程序相关的对象和属性,它实质上是跨越整个Web应用程序,包括多个页面、请求和会话的一个全局作用域。
1.由于HTTP协议是无状态的协议,所以服务端需要记录用户的状态时,就需要用某种机制来识具体的用户,这个机制就是Session.典型的场景比如购物车,
当你点击下单按钮时,由于HTTP协议无状态,所以并不知道是哪个用户操作的,所以服务端要为特定的用户创建了特定的Session,用用于标识这个用户,
并且跟踪用户,这样才知道购物车里面有几本书。这个Session是保存在服务端的,有一个唯一标识。在服务端保存Session的方法很多,内存、数据库、文件都有。
集群的时候也要考虑Session的转移,在大型的网站,一般会有专门的Session服务器集群,用来保存用户会话,这个时候 Session 信息都是放在内存的,
使用一些缓存服务比如Memcached之类的来放 Session。
2.思考一下服务端如何识别特定的客户?这个时候Cookie就登场了。每次HTTP请求的时候,客户端都会发送相应的Cookie信息到服务端。实际上大多数的应用都是用 Cookie 来实现Session跟踪的,
第一次创建Session的时候,服务端会在HTTP协议中告诉客户端,需要在 Cookie 里面记录一个Session ID,以后每次请求把这个会话ID发送到服务器,我就知道你是谁了。
有人问,如果客户端的浏览器禁用了 Cookie 怎么办?一般这种情况下,会使用一种叫做URL重写的技术来进行会话跟踪,即每次HTTP交互,
URL后面都会被附加上一个诸如 sid=xxxxx 这样的参数,服务端据此来识别用户。
3.Cookie其实还可以用在一些方便用户的场景下,设想你某次登陆过一个网站,下次登录的时候不想再次输入账号了,怎么办?这个信息可以写到Cookie里面,
访问网站的时候,网站页面的脚本可以读取这个信息,就自动帮你把用户名给填了,能够方便一下用户。这也是Cookie名称的由来,给用户的一点甜头。
所以,总结一下:Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;Cookie是客户端保存用户信息的一种机制,
用来记录用户的一些信息,也是实现Session的一种方式。
collection:
Map:
List接口存储一组不唯一(可以有多个元素引用相同的对象),有序的对象
2.Set:注重独一无二的性质
不允许重复的集合。不会有多个元素引用相同的对象。
3.Map:用Key来搜索的专家
使用键值对存储。Map会维护与Key有关联的值。两个Key可以引用相同的对象,但Key不能重复,典型的Key是String类型,但也可以是任何对象。
Arraylist底层使用的是数组(存读数据效率高,插入删除特定位置效率低)。
LinkedList底层使用的是双向循环链表数据结构(插入,删除效率特别高)。
学过数据结构这门课后我们就知道采用链表存储,插入,删除元素时间复杂度不受元素位置的影响,都是近似O(1)而数组为近似O(n),因此当数据特别多,而且经常需要插入删除元素时建议选用LinkedList.一般程序只用Arraylist就够用了,
因为一般数据量都不会蛮大,Arraylist是使用最多的集合类。
Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象、但是一个线程访问Vector ,代码要在同步操作上耗费大量的时间。Arraylist不是同步的,所以在不需要同步时建议使用Arraylist。
1.HashMap是非线程安全的,HashTable是线程安全的;HashTable内部的方法基本都经过synchronized修饰。
2.因为线程安全的问题,HashMap要比HashTable效率高一点,HashTable基本被淘汰。
3.HashMap允许有null值的存在,而在HashTable中put进的键值只要有一个null,直接抛出NullPointerException。
1.ConcurrentHashMap对整个桶数组进行了分割分段(Segment),然后在每一个分段上都用lock锁进行保护,相对于HashTable的synchronized锁的粒度更精细了一些,并发性能更好,
而HashMap没有锁机制,不是线程安全的。(JDK1.8之后ConcurrentHashMap启用了一种全新的方式实现,利用CAS算法。)
2.HashMap的键值对允许有null,但是ConCurrentHashMap都不允许。
当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。
但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让加入操作成功。(摘自我的Java启蒙书《Head fist java》第二版)。
2.comparator接口实际上是出自 java.util 包它有一个compare(Object obj1, Object obj2)方法用来排序
一般我们需要对一个集合使用自定义排序时,我们就要重写compareTo方法或compare方法,当我们需要对某一个集合实现两种排序方式,比如一个song对象中的歌名和歌手名分别采用一种排序方法的话,
我们可以重写compareTo方法和使用自制的Comparator方法或者以两个Comparator来实现歌名排序和歌星名排序,第二种代表我们只能使用两个参数版的Collections.sort().
1.对objects数组进行排序,我们可以用Arrays.sort()方法
2.对objects的集合进行排序,需要使用Collections.sort()方法
List转数组: list.toArray(arraylist.size())方法;
数组转List: Arrays的asList(arr)方法
Collection
1.List
Arraylist:数组(查询快,增删慢 线程不安全,效率高 )
Vector:数组(查询快,增删慢 线程安全,效率低 )
LinkedList:链表(查询慢,增删快 线程不安全,效率高 )
2.Set
HashSet(无序,唯一):哈希表或者叫散列集(hash table)
LinkedHashSet:链表和哈希表组成 。 由链表保证元素的排序 , 由哈希表证元素的唯一性
TreeSet(有序,唯一):红黑树(自平衡的排序二叉树。)
Map
3. HashMap:基于哈希表的Map接口实现(哈希表对键进行散列,Map结构即映射表存放键值对)
4. LinkedHashMap:HashMap 的基础上加上了链表数据结构
5. HashTable:哈希表
6. TreeMap:红黑树(自平衡的排序二叉树)
原文:https://www.cnblogs.com/sqzrlqq/p/13047907.html