本文共 15903 字,大约阅读时间需要 53 分钟。
一. Switch
1.其能接受的数据类型有四个,char , byte, short, int 2.Default 可放在switch中的任何一个地方,但只有给定的条件匹配不到时,才会执行 3.Case,default语句如果执行完要跳出,必须用break, 没的话会向下继续执行(如果碰到case语句则直接进入执行) 实例1: - int i = 1, j = 0;
- switch (i) {
- case 2:
- j += 6;
- case 4:
- j += 1;
- default:
- j += 2;
- case 0:
- j += 4;
- }
What is the value of j ? A.0 B.1 C.2 D.4 E.6
What is the acceptable type for the variable i? A.byte B.long C.float D.double E.object F.A and B G.C and D 二. String 和 StringBuffer
String 定义的是字符串常量,其値一旦定义就不再改变,如下: String s = “ABC”; S = s.subString(2); //会重新生成一个字符串对象 以上两句执行后在内存中会产生“两”个字符串对象 一个”ABC”,另一个是s指向的”AB”(注意s已不再指向”ABC”) StringBuffer 定义的是字符串变量,其値可以改变,如下: StringBuffer s1 = new StringBuffer(“ABC”); S1 = s1.subString(2); 以上两句执行后在内存中只产生“一个”字符串对象: s指向的”AB”; 三. String s = new String(“XYZ”) 产生了几个对象
该语句会产生2个字符串对象: 一个是通过 ” ” 方式在 编译期 产生,存放在常量池中 一个是通过new方式在 运行期 产生,存放在堆内存中 但在运行时只会通过new方式产生一个对象 四. java中的参数只能“按値”传递,且传递的是値的 copy
如是基本类型,则传递的是基本类型的副本 如是引用类型,则传递的是引用本身的副本 五. 方法重载和覆盖的条件
符合重载的条件: 1.在同一个类中 2.有多个同名的方法, 3.方法参数不同(参数的个数不同 或则 参数的类型不同) 实例: - public class MethodOver {
- public void setVar (int a, int b, float c) {
- }
- }
Which two overload the setVar method? (Choose Two) A.private void setVar (int a, float c, int b) { } B.protected void setVar (int a, int b, float c) { } C.public int setVar (int a, float c, int b) (return a;) D.public int setVar (int a, int b, float c) (return a;) E.protected float setVar (int a, int b, float c) (return c;) 符合覆盖的条件: 1.在继承中 2.子类中的方法名和父类相同 3.子类中的方法参数和父类相同 4.子类中的方法返回类型和父类一样 5.子类的方法不能比父类抛出更多的异常 6.子类的方法访问范围大于或等于父类 覆盖值得注意的是如果子类中有一个方法名称和父类一样,但参数不同,那不叫覆盖,所以也就不受覆盖的条件限制(注意该方法可以存在) 六. java类中的变量初始化相关的知识
6-1.初始化顺序分三步: 1. 类加载时,初始化静态变量和静态区块,先父类后子类 2. 运行中当new出一个对象时,开始为对象分配空间并初始化实例变量,先父类后子类 3. 调用构造函数时,先执行父类的构造函数,再执行子类的构造函数,具体过程是调用子类的构造函数时,在第一行处会调用父类的构造函数(显式或隐式) 6-2. 初始化时各类型的变量初始化的値: 引用类型: null 基本类型: - boolean : false
- char:\u0000
- byte: 0
- short: 0
- int: 0
- long: 0
- float: 0.0
- double: 0.0
6-3. 数组的初始化 当我们产生某个存储对象的数组时,真正产生的其实是个存储references的数组。此数组建立之后,其中的每一个reference皆会被自动设为某个特殊值。该值以关键字null表示。当Java看到null值,便将这个reference视为“不指向任何对象”。使用任何reference之前,你必须先将某个对象指派给它。如果你使用某个reference而其值为null,便会在执行期发生错误 数组在分配空间时就开始了初始化,初始化规则,基本类型按照6-2的规则进行初始化,引用类型类型全部初始化为null 6-4. java中的所有的实例变量都有系统默认初始化,所有的方法变量由方法本身进行初始化,且方法中的变量一定要初始化后才能应用 七. java中的构造函数
1. 构造函数不能被继承 2. 每一个类都至少有一个构造函数,自己不定义,编译器也会给分配一个默认的不带参数的构造函数 3. 子类的构造函数一定会调用父类的构造函数,通过super()调用,或显式或隐式,显式调用的父类构造函数必须存在; 如果没有显式调用则编译器会自动在子类的构造函数第一行处加上super()这个隐式调用,这时要求父类一定要有不带参数的构造函数存在(如果父类自己定义了构造函数,但带有参数,编译时会报错) 例子: - class super1{
- public int I = 0;
- public super1 (String text){
- I = 1;
- }
- }
- public class sub1 extends super1{
- public sub1(String text){
-
- I= 2;
-
- }
- public static void main (String args[]){
- sub1 sub2 = new sub1("Hello");
- System.out.println(sub2.I);
- }
- }
八. java中的异常处理
1. java中的异常分运行时异常 和 非运行时异常, 运行时异常由运行时系统捕获并处理(编译正常),非运行时异常必须由处理(抛出或捕获) 2. 异常机制中try{}后一定要跟catch吗? * 不一定,,但必须跟finally.也就是catch和finally必须跟其中一个 * 异常机制中try{}后一定要跟catch吗? * 不一定,,但必须跟finally.也就是catch和finally必须跟其中一个 * try { * }finally {} * 这样没问题,而且,可不是没有意义哦,因为这样可以保证即使发生了异常,finally里面的代码一定会被执行。 * 有时候,这个还是非常有用的。 * 比如可以用来释放一些自己占用的资源,然后让调用者处理异常。 3. 异常中的finally一定会执行,哪怕一个方法中有return语句,也是在异常处理后才返回 4. 异常的抛出可以先子类再父类,如果子类捕获了,则父类就不再捕获; 但是不能先父类再子类,那样会导致编译出错 5. 异常处理后,程序继续执行 实例: -
-
-
- import java.io.IOException;
- public class ExceptionTest {
-
- public static void methodA() throws IOException {
-
-
- throw new IOException();
-
-
-
- }
-
- public static void main(String[] args) {
- try {
- methodA();
-
- } catch (IOException e) {
- System.out.println("Caught1 IOException ");
- } catch (NullPointerException e) {
- System.out.println("Caught1 NullPointerException");
- } catch (Exception e) {
- System.out.println("Caught Exception");
- }
-
- System.out.println("main exit");
- }
- }
九. 按位运算和逻辑运算
按位运算操作符(& ,| )两边的都要计算 逻辑运算如果操作符(&&, || )左边成立则就不在计算右边了 实例: - public class test {
- private static int j = 0;
-
- private static boolean methodB(int k) {
- j += k;
- return true;
- }
-
- public static void methodA(int i) {
- boolean b;
- b = i < 10 | methodB(4);
- b = i < 10 || methodB(8);
- }
-
- public static void main(String args[]) {
- methodA(0);
- System.out.println(j);
- }
- }
What is the result? A.The program prints “0” B.The program prints “4” C.The program prints “8” D.The program prints “12” E.The code does not complete 十. for(;;)意义
相当于while(true), 不知道java为什么要搞出这个古怪让人费解的东西? 十一. equals, = =
equals比较两个对象的内容是否相等 = = 比较的是两个引用是否指向同一对象 String的存储特性会对以上的判定规则产生影响(实质上规则不变,表面上改变): String 通过“”方式生成的对象会存储在常量池中,常量池有一个重要的特点就是共享,比如String s = “X”; 在把”X”放常量池之前jvm会检测常量池中是否存在和“X"相同的对象,如果已经存在则直接把引用指向已存在的对象,不再为”X”分配空间,好处是节约了空间 何时需要重写equals() 当一个类有自己特有的“逻辑相等”概念(不同于对象身份的概念)。 2.设计equals() [1]使用instanceof操作符检查“实参是否为正确的类型”。 [2]对于类中的每一个“关键域”,检查实参中的域与当前对象中对应的域值。 [2.1]对于非float和double类型的原语类型域,使用==比较; [2.2]对于对象引用域,递归调用equals方法; [2.3]对于float域,使用Float.floatToIntBits(afloat)转换为int,再使用==比较; [2.4]对于double域,使用Double.doubleToLongBits(adouble) 转换为int,再使用==比较; [2.5]对于数组域,调用Arrays.equals方法。 3.当改写equals()的时候,总是要改写hashCode() 根据一个类的equals方法(改写后),两个截然不同的实例有可能在逻辑上是相等的,但是,根据Object.hashCode方法,它们仅仅是两个对象。因此,违反了“相等的对象必须具有相等的散列码”。 4.设计hashCode() [1]把某个非零常数值,例如17,保存在int变量result中; [2]对于对象中每一个关键域f(指equals方法中考虑的每一个域): [2.1]boolean型,计算(f ? 0 : 1); [2.2]byte,char,short型,计算(int); [2.3]long型,计算(int) (f ^ (f>>>32)); [2.4]float型,计算Float.floatToIntBits(afloat); [2.5]double型,计算Double.doubleToLongBits(adouble)得到一个long,再执行[2.3]; [2.6]对象引用,递归调用它的hashCode方法; [2.7]数组域,对其中每个元素调用它的hashCode方法。 [3]将上面计算得到的散列码保存到int变量c,然后执行 result=37*result+c; [4]返回result。 十二. 基本类型的变量赋初始値
Byte的范围为-128~127 当我们给出一个整数,且该整数后不带l标示,则编译器自动把它视为int类型,如 Int i = 1 ; 是成立的 当我们给出一个小数,且该小数后不带f标示,则编译器自动把它视为double类型,如 Double d = 1.0; 是成立的 十三. 基本类型的转化
规则: 小的可以自动转化为大的, 大的要强制性才能转为小的,比如以下 Double d = 1.0f; //正确, 小转大,自动 Float f = 1.0d(或1.0); //错误,大转小,需强制 float f = (float)1.0d; 十四. servlet运行机理
Servlet是java引入的在B/S架构中用来处理动态网页的一种技术,其实质是一个继承了HttpServlet的java类,由web容器负责解释运行,其机理如下: (第一次被请求) 客户提出请求 -> web容器解析请求,找出请求的url,根据web.xml配置找到对应的servlet -> 加载servlet -> 实例化 -> 调用init初始化 -> 调用service方法 -> 由service方法自动匹配doXXX方法-> web容器关闭/servlet长时间没有被请求则调用其destroy方法销毁servlet实例 不确定的地方: servlet多长时间没有被调用才会销毁,可以设置吗? 不同的web服务器应该是不同的吧 十五. servlet 和 jsp 的区别
都是用来处理动态网页的技术,jsp被编译后转化为servlet, 一个jsp页面本质上也是一个servlet;jsp在第一次被请求后,先转化为servlet,再编译,所以第一次要比servlet慢 Servlet是在java代码中嵌入HTML, 擅长逻辑控制 Jsp是在HTML中嵌入java代码, 擅长页面处理 十六. forward(请求转发)与redirect(重定向)的区别
( Forward是服务器端请求,是servlet提供的一种技术,服务器根据请求的url找到请求的页面,对浏览器而言,这一过程是不透明的,好像什么也没发生一样,浏览器的地址栏不会显示被请求的url页面地址(显示的仍是上次请求的服务器端的url地址),从HTTP协议的角度,只发生一次的请求响应过程 Redirect是客户端的请求,客户端根据服务器传回的地址,重新向服务器发出请求,浏览器的地址栏显示的是新请求的url地址, 从http协议的角度,发生了两次请求响应的过程 ) ------------------- 1. 重定向是HTTP协议定义的功能,要经过两次HTTP通信过程,第一次用于获取资源的实际地址,第二次用之前得到的地址发出请求, 这个过程对浏览器是可见的; 请求转发是servlet技术本身的特点,转发的过程是在服务器内部进行,对浏览器是不透明的,它认为它所发送的地址实际上得到的就是这些内容; 从HTTP角度看,只有一次通讯过程 2. 重定向只能转向新的资源,功能较单一; 请求转发不但可以转向新的资源,也可将其它资源和本身的生成的内容结合起来,功能很丰富 十七. 线程
16-1.线程的同步 1.同步的概念: 当多个线程同时使用一个对象时,由于线程本身运行的不确定性,可能会造成操作的不完整性,故而引入同步 2.Java中同步的方式有两种, Synchronized 和 Lock 3.当一个线程进入一个对象的同步方法后,它会把该对象锁住,其它的线程不能再使用该对象(包括对象的任何方法,属性),直到该线程释放掉锁,其它线程才有机会使用该对象 4.一个线程释放同步锁的条件: a. 正常运行完(退出synchronized块) b. 使用wait()方法 5.同步中的方法: wait(), notify()/notifyAll(),用于同步中的线程通讯 Wait(): 释放持有的同步锁,本身进入锁等待状态,在线程中因为多个线程“同时“运作,可能导致运作的条件不满足,当条件不满足时,线程本身就需要进入等待状态(释放掉锁),等其它的线程改变了条件,它才能有机会继续执行 NotifyAll(): 唤醒锁等待的线程,当一个持有线程锁的对象调用该方法后,其它处于锁等待的线程虽然被唤醒,但其本身不会立刻释放掉锁,需要等运行结束后(退出synchronized块)才释放掉,其它线程才有机会执行 16-2.线程中的方法 6.sleep() ,当前线程休眠一个设定的时间,时间到后进入线程就绪队列,等待执行 7.join(),该方法使调用该方法的线程在此之前执行完毕,也就是等待调用该方法的线程执行完毕后再往下继续执行。注意该方法也要捕获异常。 实例: - class A implements runable {
- int i;
- public void run() {
- try {
- thread.sleep(5000);
- i = 10;
- } catch (InterruptedException e) {
- }
- }
- }
-
- public class Test {
- public static void main(string args[]) {
- try {
- A a = new A();
- Thread t = new Thread(a);
- t.start();
-
- int j = a.i;
-
- } catch (Exception e) {
- }
- }
- }
Which statement al line 17 will ensure that j=10 at line 19? A.a.wait(); B.t.wait(); C.t.join(); D.t.yield(); E.t.notify(); F.a.notify(); G.t.interrupt();
8.yield(),与sleep()类似,只是不能由用户指定暂停多长时间,所以一个线程线程执行yield()方法后,也可能立刻执行(jvm还是分配给它执行),yield()方法只能让同优先级的线程有执行的机会。 举几个例子: -
- class SyncStack{
- private int index = 0;
- private char []buffer = new char[6];
- public synchronized void push(char c){
- while(index = = buffer.length){
- try{
- this.wait();
- }catch(InterruptedException e){}
- }
- this.notify();
- buffer[index] = c;
- index++;
- }
- public synchronized char pop(){
- while(index ==0){
- try{
- this.wait();
- }catch(InterruptedException e){}
- }
- this.notify();
- index- -;
- return buffer[index];
- }
- }
- class Producer implements Runnable{
- SyncStack theStack;
-
-
- public Producer(SyncStack s){
- theStack = s;
- }
- public void run(){
- char c;
- for(int i=0; i<20; i++){
- c =(char)(Math.random()*26+'A');
- theStack.push(c);
- System.out.println("Produced: "+c);
- try{
- Thread.sleep((int)(Math.random()*1000));
- }catch(InterruptedException e){}
- }
- }
- }
- class Consumer implements Runnable{
- SyncStack theStack;
- public Consumer(SyncStack s){
- theStack = s;
- }
- public void run(){
- char c;
- for(int i=0;i<20;i++){
- c = theStack.pop();
- System.out.println("Consumed: "+c);
- try{
- Thread.sleep((int)(Math.random()*1000));
- }catch(InterruptedException e){}
- }
- }
- }
- public class SyncTest{
- public static void main(String args[]){
- SyncStack stack = new SyncStack();
-
- Runnable source=new Producer(stack);
- Runnable sink = new Consumer(stack);
- Thread t1 = new Thread(source);
- Thread t2 = new Thread(sink);
- t1.start();
- t2.start();
- }
- }
-
- import java.util.LinkedList;
- public class Stack {
- LinkedList list = new LinkedList();
-
- public synchronized void push(Object x) {
- synchronized (list) {
- list.addLast(x);
- notify();
- }
- }
-
- public synchronized Object pop() throws Exception {
- synchronized (list) {
- if (list.size() <= 0) {
- wait();
- }
- return list.removeLast();
- }
- }
- }
对例2的分析【网友】: 当一个线程执行下面方法: - public synchronized void push(Object x) {
- synchronized(list) {
- list.addLast( x );
- notify();
- }
- }
这个时候他获得2个锁,一个是Stack对象的锁,还有list对象的锁,而notify,释放的是stack对象的锁,没有释放list对象的锁,所以只要当pop方法中检测到list的大小为0,则执行pop的线程会一直控制list的锁,使得push没法执行。 之所以大部分时间程序运行成功,是因为push总比pop快,list没有为0. -
- public class SyncTest {
- public static void main(String[] args) {
- final StringBuffer s1 = new StringBuffer();
- final StringBuffer s2 = new StringBuffer();
- new Thread() {
- public void run() {
- synchronized (s1) {
- s2.append("A");
- synchronized (s2) {
- s2.append("B");
- System.out.print(s1);
- System.out.print(s2);
- }
- }
- }
- }.start();
-
- new Thread() {
- public void run() {
- synchronized (s2) {
- s2.append("C");
- synchronized (s1) {
- s1.append("D");
- System.out.print(s2);
- System.out.print(s1);
- }
- }
- }
- }.start();
- }
- }
对例3的分析【网友】 如果没有出现死锁,那么输出的结果必然是:"ABABCD"; 如果没有输出此结果;那么死锁 原因:T1启动在前, T2启动在后;且T1的第一步操作为:synchronized(s1) 1. 由于T1执行过慢---> T2要执行第一步:synchronized(s2)--->寻找s1,被T1锁住等待--->T1寻找说说s2,被T2锁住等待 ; 出现死锁 2. T1执行过快-->s1,s2都被锁住--->T2执行,等待-->T1执行完:"AB" -->T2执行:"ABCD" 十八.web服务器
Web服务器说白了就是提供web应用的基础功能: 1. 它是遵从http协议的一个服务器端程序,按照http提供基本的请求解析、应答处理等 2. 它提供了供web程序运行的最直接的环境,比如tomcat就是一个servlet的容器 3. 它提供了对线程的管理,包括创建,调度,撤销等 4. 它提供请求地址与具体地址的对应处理 。。。 B/S是在C/S架构基础上发展起来的一种技术,相比C/S,B/S主要有以下几点的不同,这里不比较哪个优越,况且优越与否是和具体环境关联的,单独不能说哪个好, 1. B/S是遵从http协议的,即采用的是标准的协议, 2. B/S的客户端已开发好(就遵从http协议的浏览器),不需要程序员再开发 3. B/S的服务器端业界也提供了基础功能的实现(各种web容器) 一个C/S示例(多线程),希望在它的基础上能更好的理解web服务器 1. 客户端程序:MultiTalkClient.java - import java.io.*;
- import java.net.*;
- public class MultiTalkClient {
- public static void main(String args[]) {
- try{
- Socket socket=new Socket("127.0.0.1",4700);
-
- BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
-
- PrintWriter os=new PrintWriter(socket.getOutputStream());
-
- BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
-
- String readline;
- readline=sin.readLine();
- while(!readline.equals("bye")){
-
- os.println(readline);
-
- os.flush();
-
- System.out.println("Client:"+readline);
-
- System.out.println("Server:"+is.readLine());
-
- readline=sin.readLine();
-
- }
- os.close();
- is.close();
- socket.close();
- }catch(Exception e) {
- System.out.println("Error"+e);
- }
- }
2. 服务器端程序: MultiTalkServer.java - import java.io.*;
- import java.net.*;
- import ServerThread;
- public class MultiTalkServer{
- static int clientnum=0;
- public static void main(String args[]) throws IOException {
- ServerSocket serverSocket=null;
- boolean listening=true;
- try{
- serverSocket=new ServerSocket(4700);
-
- }catch(IOException e) {
- System.out.println("Could not listen on port:4700.");
-
- System.exit(-1);
- }
- while(listening){
- new ServerThread(serverSocket.accept(),clientnum).start();
-
- 客户计数创建服务线程,并启动之
- clientnum++;
- }
- serverSocket.close();
- }
- }
3. 程序ServerThread.java - import java.io.*;
- import java.net.*;
- public class ServerThread extends Thread{
- Socket socket=null;
- int clientnum;
- public ServerThread(Socket socket,int num) {
- this.socket=socket;
- clientnum=num+1;
- }
- public void run() {
- try{
- String line;
- BufferedReader is=new BufferedReader(new InputStreamReader(socket.getInputStream()));
-
- PrintWriter os=newPrintWriter(socket.getOutputStream());
-
- BufferedReader sin=new BufferedReader(new InputStreamReader(System.in));
-
- System.out.println("Client:"+ clientnum +is.readLine());
-
- line=sin.readLine();
-
- while(!line.equals("bye")){
-
- os.println(line);
-
- os.flush();
-
- System.out.println("Server:"+line);
-
- System.out.println("Client:"+ clientnum +is.readLine());
-
- line=sin.readLine();
-
- }
- os.close();
- is.close();
- socket.close();
- server.close();
- }catch(Exception e){
- System.out.println("Error:"+e);
-
- }
- }
- }
十九.资源池的理解
1.资源池引入的目的(好处) 提高性能 2.资源池运作机制 由资源池管理器提供一定数目的目标资源,当有请求该资源时,资源池分配给一个,然后给该资源标识为忙,标示为忙的资源不能再被分配使用,当某一个资源使用完后,资源池把相关的资源的忙标示清除掉,以示该资源可以再被下一个请求使用 3.资源池常有的参数 1.初始资源的数目:资源池启动时,一次建立的资源数目,资源池最少要保证在这个数目上 2.最大资源的数目:当请求的资源超出这个数目,就等待 4.常见的资源池 1.数据库连接池 2.web容器中的request,response对象池 3.web容器中的线程池 转载地址:http://gsfbi.baihongyu.com/