JAVA学习首页投稿(暂停使用,暂停投稿)Java学习笔记

读书笔记--Java高级程序设计 之 Java后端入门准备

2016-11-19  本文已影响448人  androidjp

主要是对一个Java开发的注意点和易忘点做个小总结,不少地方没有详细分析,读者见谅。另外,对一些特殊的示例程序做一些笔记。

一、Integer 内部的IntegerCache类对象,缓存了从-128~127的整数(因为这些小的整数可能较为常用,所以提前缓存在内存中),也是常量池的一种运用。

Class cache = Integer.class.getDeclaredClasses()[0];//IntegerCache.java 这个类的类类型
        Field myCache  =  cache.getDeclaredField("cache");//通过这个类类型反射获取到类对象
        myCache.setAccessible(true);///将该类对象的所有属性和方法的访问权限都变为public
        Integer[] newCache = (Integer[]) myCache.get(cache);///调用这个反射获得者的方法
        System.out.printf("看一下这个newCache 缓存数组的首元素,是不是 -128? newCache[0]=%d\n",newCache[0]);
        System.out.printf("所以,newCache[128]=%d\n",newCache[(0+128)]);
        newCache[132] = newCache[133];// 这个数组的第133个元素, 值为: 5
        int a =2;
        int b =a+a;//实际指向了 cache数组的
        System.out.printf("%d + %d = %d\n" , a,a,b);
        System.out.println(newCache[128+3]);

        ////看看大整数和小整数的区别
        Integer big1 = 1000;
        Integer big2 = 1000;
        Integer sm1 = 127;
        Integer sm2 = 127;
        System.out.println(big1==big2);///这里可以看出,比127大的数,会在堆中新建一个Integer类对象,所以,两个Integer对象引用指向两个不同位置的Integer类对象
        System.out.println(sm1==sm2);///而在Integer类中,[-128,127]区间里的整数,都会先在IntegerCache类中的常量池里查找,并索引之,所以,sm1和sm2指向同一个位置
        ///这里,由于上述的代码"newCache[132]==newCache[133]"的缘故,即newCache[sm1+128]== newCache[sm2+128],而newCache[sm1+128]=newCache[sm2+128]= -128+128+5 = 5
        ///所以,sm1 和 sm2 的指向的常量池下标对应的值都是5,于是,sm1 == sm2
        sm1 = 4;
        sm2 = 5;
        System.out.printf("sm1=%d,sm2=%d,sm1=sm2吗?%b\n",sm1,sm2,sm1==sm2);
        //而这里,就是正常的情况
        sm2 = 6;
        System.out.printf("sm1=%d,sm2=%d,sm1=sm2吗?%b\n",sm1,sm2,sm1==sm2);

运行结果如下:

看一下这个newCache 缓存数组的首元素,是不是 -128? newCache[0]=-128
所以,newCache[128]=0
2 + 2 = 5
3
false
true
sm1=5,sm2=5,sm1=sm2吗?true
sm1=5,sm2=6,sm1=sm2吗?false

二、泛型注意点:通配符+边界,List<? super X>只能添加X类及其子类对象元素(因为? super X表示:X及其父类,存在一定的不确定性)

        List<? super Mother> list  = new ArrayList<Mother>();
        Me me = new Me();///Me extends Mother
        Sister sister = new Sister();//Sister extends Mother
        Mother mother = new Mother();//Mother extends Grandpa
        Grandpa grandpa = new Grandpa();
        Son son = new Son();
        list.add(me);
        list.add(son);
        list.add(sister);
        list.add(mother);
//        list.add(grandpa);  //不合法

三、Java常用注解与自定义注解

@Deprecated///表示这个Person类是过时的类
class Person{
    @SuppressWarnings(value = "unused")///无须抛出 未使用警告
    private String name;

    @Deprecated///表示过时的方法
    public void speak(){
    }

    @Override///表示重载的方法
    public String toString() {
        return super.toString();
    }
    @SuppressWarnings("unused")
    public void working(){
        @SuppressWarnings({"unchecked", "unused"})///无须抛出检测警告和未使用警告
        List list=new ArrayList();
    }
}
@Target(ElementType.FIELD)///注解@JP用于修饰方法
@Retention(RetentionPolicy.RUNTIME)//注解@JP能够保留到运行时
public @interface ID {
        public String value();///快捷参数value,可用于快捷赋值
        public String description() default "";
}  
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@SuppressWarnings("unused")
public @interface Entity {
         String name() default "用户";
         ID id() default @ID("007");///①Entity内部可拥有@ID注解参数 ②快捷赋值给value为007:@ID("007")
}

四、Java网络编程

五、多线程

  1. 线程操作相关基础:
  1. 例子:线程的run()方法中对中断做出响应的正确写法:
while(还有工作没完成){
  if(Thread.currentThread().isInterrupted())
  {///如果中断状态被设为true(别人叫我中断了)
    ///响应中断请求。首先决定是否终止线程,如果要终止,需要完成必须完成的结束工作
    ///例如关闭资源占用等,然后退出run()方法
  }
  ///处理未完成工作
}
  1. 未捕获异常,用Thread.UncaughtExceptionHandler来解决。
  1. Lock的用法
  1. 线程的六个状态
  2. 新生:new出了Thread对象,还没执行start()。
  3. 可运行:调用start()后的状态。【注意:此状态下,线程不一定被线程调度器加载到CPU上执行】
  4. 阻塞:受阻塞并正在等待锁的线程状态,没有CPU时间片。两种方法进入阻塞态:①线程进入synchronized方法或代码块(或调用Lock对象的lock()或tryLock()等方法),并试图获取其他线程已经占用的锁时;②退出等待状态、并试图重新获得在等待状态时拥有的锁但此锁已被其他线程占用时。
  5. 等待:此状态下的线程正在等待另一个线程,以执行特定操作。不占CPU时间片。
  6. 计时等待:具有指定等待时间的某一等待线程的线程状态。与等待状态相似,区别是:过了等待时间,也会退出等待状态。
  7. 终止:线程结束执行。进入此状态的两种可能:① run()方法执行完毕并返回; ② 在执行run()过程中抛出未处理异常。
  8. 示例:Condition.await()和Condition.signal()的应用:多个转账交易可以被多个线程调用,而遇到转账金额过大的情况,就选择等待其他交易完成。
    Condition相对于对象锁的优势:能够在一个锁对象上创建多个Condition对象,每个Condition对象代表一种不同的等待类型。
    private Account[] accounts;
  private Lock dealLock = new ReentrantLock();
  private Condition moneyCondition = dealLock.newCondition();///资金不足的情况

  public void deal(int fromAccount,int toAccount,Long money){
      if (this.dealLock.tryLock()){
          try {
              while(accounts[fromAccount].money<money){
                  ///如果存款不足,就不能转这么多帐了
                  try {
                      moneyCondition.await();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }

              ///到有了存款了,那么,就可以继续执行转账
              accounts[fromAccount].money -= money;
              accounts[toAccount].money += money;

              /////转账完毕,可以唤醒其他需要转账的线程了
              moneyCondition.signalAll();
          }   finally {
              this.dealLock.unlock();
          }
      }
  }

以上代码的功能于一下使用synchronized同步关键字的一样:

  public synchronized void deal(int fromAccount, int toAccount, Long money) {
      while (accounts[fromAccount].money < money) {
          ///如果存款不足,就不能转这么多帐了
          try {
              this.wait();
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
      }
      ///到有了存款了,那么,就可以继续执行转账
      accounts[fromAccount].money -= money;
      accounts[toAccount].money += money;

      this.notifyAll();//转账完毕,可以唤醒其他需要转账的线程了
  }
  1. 同步器之---信号量(Semaphore)
    信号量的作用是限制对共享资源读写的线程的最大并发数。它一般配合具有同步能力的资源接口方法一起使用。而信号量本身的阻塞过多线程的能力与共享数据的同步操作之间,是不同的处理,也就是说:能够被信号量允许的线程,也还得需要经过同步方法的同步过程,才能真的达到共享资源的同步读写。
///例子:10个线程 ,同时对共享数据进行读取,通过信号量限制每次最多5个线程异步运行。
///,剩下的线程被阻塞,而运行的5个线程,如果要做同步操作,也必须遵循先后的原则。
public class PoolSemaphoreDemo {
    private static final int max =5;
    private final Semaphore semaphore = new Semaphore(max,true);

    public static void main(String[] args){
        final PoolSemaphoreDemo pool = new PoolSemaphoreDemo();
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                try {
                    Object obj;
                    obj = pool.getItem();///读写数据,设置数据状态为"被占用"
                    if (obj!=null)
                    System.out.println("线程:"+Thread.currentThread().getName()+"读取了数据:"+obj.toString());
                    else
                        System.out.println("线程:"+Thread.currentThread().getName()+"没有数据");
                    Thread.sleep(1000);
                    pool.putItem(obj);//读写数据完毕,设置数据为"空闲"状态,并容许后续的等待线程调用
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }

            }
        };
        for (int i=0;i<10;i++){
            Thread t = new Thread(runnable,"thread"+i);
            t.start();
        }
    }

    public Object getItem() throws InterruptedException {
        System.out.println(Thread.currentThread().getName()+"正在被信号量检查。。。");
        semaphore.acquire();
        System.out.println(Thread.currentThread().getName()+"被允许执行同步方法");
        return getNextAvailableItem();
    }

    public void putItem(Object x){
        if (markAsUnused(x)){
            semaphore.release();
            System.out.println("线程:"+Thread.currentThread().getName()+"释放了资源:"+x.toString());

        }
    }

    protected Object[] items = {"11","22","33"};
    protected boolean[] useds = new boolean[3];

    private synchronized Object getNextAvailableItem() {
        for (int i=0;i<3;i++){
            if (!useds[i]){
                useds[i] = true;
                return items[i];
            }
        }
        return null;
    }

    private synchronized boolean markAsUnused(Object item){
        for (int i=0;i<3;i++){
            if (item == items[i]){
                if (useds[i]) {///正在被使用
                    useds[i] = false;
                    return true;
                }else///没有被使用
                    return false;
            }
        }
        return false;
    }
}
  1. 同步器之---倒计时门栓(CountDownLatch)
    是一个同步辅助器。下面通过一个例子,说明他的用法:
public class LatchDriverDemo {

    public static void main(String[] args) throws InterruptedException {
        CountDownLatch startSignal = new CountDownLatch(1);
        CountDownLatch doneSignal = new CountDownLatch(5);

        //主线程运行
        for (int i=0;i<5;i++){
            new Thread(new Worker(startSignal,doneSignal),"t"+i).start();
        }
        //此时,5个子线程都执行了CountDownLatch.await()从而等待主线程开门,主线程继续运行

        ///此时,5个子线程处于等待状态,主线程休眠4s
        Thread.sleep(4000);
        // 此时,主线程执行CountDownLatch.countDown(),使得由于startSignal的值已经减为0从而解放5个子线程,子线程开始继续往下执行,主线程继续执行
        startSignal.countDown();///startSignal变成0,所有线程开始工作

        ///此时,子线程继续执行中,主线程调用了await(),所以主线程阻塞了,等待doneSignal的值变为0,才被允许继续执行
        doneSignal.await();

        ////然后,子线程开始做。。。。。。。

        System.out.println("所有任务完成!");
    }
}
class Worker implements Runnable{

    private final CountDownLatch startSignal;
    private final CountDownLatch doneSignal;

    public Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
        this.startSignal = startSignal;
        this.doneSignal = doneSignal;
    }

    @Override
    public void run() {
        try {
            //上门栓,等待主线程的开门(startSignal减为0)
            startSignal.await();
            /*
              do sth
             */
            //完成任务,doneSignal减一(减到0,主线程才会被唤醒)
            doneSignal.countDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
  1. 同步器之---障栅(CyclicBarrier)
     允许一组线程相互等待,直到到达某个公共屏障点。优点:能够循环多次地进行(等待--运行)的状态切换,从而实现线程间的复杂协作过程。
     例子说明一切:快的线程,会等待慢的线程执行完,每次达到同一个进度,就再次解放所有线程,继续往下执行。
public class CyclicBarrierTest {
    public static void main(String[] args){
        CyclicBarrier barrier = new CyclicBarrier(2, new Runnable() {
            @Override
            public void run() {
                System.out.println("人齐了!!");
            }
        });
        new Thread(new Tour(barrier,"小明走路",1)).start();
        new Thread(new Tour(barrier,"小花开车",2)).start();
    }
    static class Tour implements Runnable{
        ///走路到:广州、深圳、珠海的时间
        private int walkTime[] = {5,5,5};
        //开车到:广州、深圳、珠海的时间
        private int driveTime[] = {3,3,3};
        private CyclicBarrier barrier;
        private String name;
        private int way;
        public Tour(CyclicBarrier barrier,String name,int way) {
            this.barrier = barrier;
            this.name = name;
            this.way = way;
        }
        @Override
        public void run() {
            try{
                Thread.sleep(1000*((way==1)?walkTime[0]:driveTime[0]));
                System.out.println(this.name+"到广州了");
                barrier.await();
                Thread.sleep(1000*((way==1)?walkTime[1]:driveTime[1]));
                System.out.println(this.name+"到深圳了");
                barrier.await();
                Thread.sleep(1000*((way==1)?walkTime[2]:driveTime[2]));
                System.out.println(this.name+"到珠海了");
                barrier.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (BrokenBarrierException e) {
                e.printStackTrace();
            }
        }
    }
}
  1. 同步器之--交换器(Exchanger)
     顾名思义, 就是进行线程间数据交换的。实现方法为:Exchanger.exchange(Object obj):Object

六、序列化

}
```

七、JDBC

public class MyCon {
public static final int FREE = 100;///空闲
public static final int BUZY = 101;///繁忙
public static final int CLOSED = 102;///连接关闭
private Connection connection;//持有Connection对象的引用
private int state= FREE;///当前的连接状态
public MyCon(Connection connection) {
this.connection = connection;
}
/**
* @return 返回数据库连接,用于操作
/
public Connection getConnection() {
return connection;
}
/
*
* @return 当前状态
*/
public int getState() {
return state;
}

/**
 * @param state 设置当前状态
 */
public void setState(int state) {
    this.state = state;
}

}

* ConPool.java 【数据库连接池】

public class ConPool {
private List<MyCon> freeCons = new ArrayList<>();
private List<MyCon> buzyCons = new ArrayList<>();
private int max = 10;
private int min = 2;
private int current = 0;
private static ConPool sInstance;
private ConPool(){
while(this.min > this.current){
this.freeCons.add(this.createCon());
}
}
public static ConPool getInstance(){
if (sInstance==null){
synchronized (ConPool.class){
if (sInstance==null)
sInstance = new ConPool();
}
}
return sInstance;
}

/**
 * 获取数据库连接
 * @return 数据库连接
 */
public MyCon getCon() {
    MyCon myCon = this.getFreeCon();
    if (myCon!=null)
        return myCon;
    return this.getNewCon();
}

/**
 * 设置连接为空闲状态
 * @param con 连接
 */
public void setFree(MyCon con){
    this.buzyCons.remove(con);
    con.setState(MyCon.FREE);
    this.freeCons.add(con);
}

/**
 * @return 返回当前连接池的连接状态
 */
public String toString(){
    return "当前连接数:"+ this.current + ",空闲连接数:"+this.freeCons.size()+",繁忙连接数:"+this.buzyCons.size();
}
//=================================================================================
private MyCon getNewCon() {
    if (this.current>=this.max)
        return null;
    MyCon myCon = this.createCon();
    assert myCon != null;
    myCon.setState(MyCon.BUZY);
    this.buzyCons.add(myCon);
    return myCon;
}

private MyCon createCon() {
    try{
        Connection connection = MySqlDAO.getConnection();
        MyCon myCon = new MyCon(connection);
        this.current++;
        return myCon;
    } catch (Exception e) {
        e.printStackTrace();
    }
    return null;
}

private MyCon getFreeCon() {
    if (freeCons.size()>0){
        MyCon con  =freeCons.remove(0);
        con.setState(MyCon.BUZY);
        this.buzyCons.add(con);
        return con;
    }
    return null;
}

}

* MySqlDAO.java【MySql的连接驱动操作工具类】

public class MySqlDAO {

public static String database = null;

public static Connection getConnection() throws Exception{
    String driverName="com.mysql.jdbc.Driver";
    String url = "jdbc:mysql://localhost:3306/"+(database==null?"":database);///连接协议 + 数据库地址+ 数据库名称
    String user = "root";
    String password="110120130140";
    Class.forName(driverName);///加载数据库驱动,此过程会自动调用DriverManager中的registerDriver(Driver driver)方法,注册到管理器中
    Connection con = DriverManager.getConnection(url,user,password);////创建并获取连接
    return con;//等待并最终返回连接信息
}
//。。。。。。。。。。

}


#### 八、IntelliJ IDEA上第一个后端项目的创建过程。
关于eclipse或MyEclipse上新建Web工程,网上比较全,这里不多介绍,而IDEA上创建web项目的过程,可以参考[这篇文章](http://blog.csdn.net/u012532559/article/details/51013400),亲测成功。

由于篇幅问题,关于Servlet注意点与Java Web开发规范等,将后续更新,谢谢阅读~
上一篇下一篇

猜你喜欢

热点阅读