美文网首页
记录java一些东西

记录java一些东西

作者: wenou | 来源:发表于2017-09-13 11:39 被阅读5次

1.调用泛型方法

public static void main(String[] args) {
    String[] s1 = {"1", "3", "5"};
    test.<String>print(s1);
}

public static <T> void print(T[] data) {
    for (int i = 0; i < data.length; i++) {
        System.out.println(data[i]);
    }
}

使用.<类型>函数方法的方式调用泛型方法,而此<类型>是可以省略的。

2.泛型类型的定义

  1. 定义类为泛型类型,需要将泛型类型放在类的后面 如public class test<T>
  2. 定义方法为泛型类型,需要将泛型类型写在方法返回类型的前面。如public static <T> void print(T[] data)

3.泛型通配符

为了避免上面的问题,我们使用通配符来解决。

通配符的三种形式

  1. ? 非限制通配符,和? extends object一样
  2. ? extends T 上限通配,也就是必须是T的子类型(包含T)
  3. ? supter T 下限通配,也就是必须是T的父类型(包含T)

4.类型擦除

java中的泛型使用的是类型擦除的方法实现的。泛型只存在于编译阶段,而在运行阶段是不存在泛型类型的,一旦编译器在编译时期检测类型是安全的,就会将它转换为原始类型。

下面是编译完成后的.class运行时文件:

img

也就是说在运行时是没有泛型这一概念的,泛型只在编译期用于检测类型安全。

为什么new E()是错误的?

java中,不能直接创建泛型的对象,因为创建对象是在运行时动态创建的,而运行时是没有泛型类型的。

5.泛型的几种常见的限制

  1. 不能使用new E(),也就是不能创建泛型对象
  2. 不能使用new E[],也就是不能创建泛型数组
  3. 静态方法不能使用类的泛型类型作用参数
  4. 异常类不能是泛型的

6.Collections

1.Collections.nCopies

使用此方法可以创建指定对象的n个副本的不可变list。此方法接收一个对象,并接收一个int count的参数来指定要创建几个该对象的副本。也就是说,此list中会有n个该对象的副本,而且此list是不可变的,也就是不进对该list进行修改的操作。否则,会报错:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)
    at generic.test.main(test.java:19)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:147)

2.Collections.fill

表示用指定元素填充(覆盖)原集合中的所有元素。

    List<Integer> mDatas = new ArrayList<>();
    mDatas.add(1);
    mDatas.add(2);
    mDatas.add(3);
    Collections.fill(mDatas, 4);

打印结果为4 4 4

3.使用Collections建立单元素和不可变的集合和map

图片

7.Map类型及作用

常用的Map类有hashMaplinkedHashMapTreeMap

  1. 如果更新map时不需要保持元素的顺序,就用HashMap
  2. 如果需要按插入时间或最后访问时间来排序,就用LinkedHashMap
  3. 如果需要按键来进行排序,就使用TreeMap

TreeMap例子

对一段字符串进行分割,然后统计每个被分割部分的单词出现的次数,并按字母的自然顺序进行排序。

图片

8.算法时间复杂度的计算

在计算算法的时间复杂度时,我们主要看算法时间的增加,主要是由哪个变量引起的,就取此值,写法为O(值)。比如:

img

下面是关于指数级的时间复杂度的计算:


img

各时间复杂度的对比关系:


img

9.优化的求最大公约数的算法

private static int getMaxGCD(int m, int n) {
        int gcd = 1;
        if (m % n == 0) {
            return n;
        }
        for (int i = n / 2; i >= 1; i--) {
            if (m % i == 0 && n % i == 0) {
                gcd = i;
                break;
            }
        }
        return gcd;
    }

最优化的方法:

private static int getMaxGCD(int m, int n) {
        if (m % n == 0) {
            return n;
        }
        return getMaxGCD(n, m % n);
    }

10.StringTokenizer的用法

StringTokenizer的作用主要是根据指定的分割符将字符串分割成n部分,然后通过hasMoreToken来判断是否还有下一个被分割的部分,nextToken的方法来获取对应的数据。

    StringTokenizer stringTokenizer = new StringTokenizer("www.baidu.com", ".a", true);
    while (stringTokenizer.hasMoreTokens()) {
        System.out.println("token:" + stringTokenizer.nextToken());
    }

上面的参数二,表示按.或者a来对字符串进行分割,也就是遇到.或者a就进行分割,默认本身不被算作分割的部分。
参数三,表示将本身也算作分割的一部分。

上面的结果为:

token:www
token:.
token:b
token:a
token:idu
token:.
token:com

11.二叉查找树

二叉查找树的特征:对于树中的每一个节点,它的左子树中的节点都是小于当前节点的值的;而它的右子树中的节点都是大于当前节点的值的。

判断是否包含某个元素

在二叉树中添加一个元素

img

在二叉树中添加一个元素,有两种情况:

  1. 二叉树中已经存在此元素,会直接丢弃要插入的元素
  2. 将元素添加到某个叶子节点的下一层,也就是最底层。

从上面的代码示例子,可以得知,当current为null,也就是while循环结束后,就是添加元素所要插入的位置了。通过此元素创建新节点,然后与parent的值进行比较,大于就添加到右边,小于就添加到左边。

中序遍历

递归地先遍历左子树,然后访问当前节点,最后右子树。中序遍历法以递增顺序显示BST中的所有节点。

img

后序遍历

首先递归地遍历左子树,然后递归地遍历右子树,最后访问该节点本身。


img

前序遍历

首先递归访问当前节点,然后递归地访问该节点的左子树,最后递归地访问该节点的右子树。


img

广度优先遍历

逐层访问树中的节点。首先访问根节点,然后从左往右访问根节点的孩子节点,然后再从左住右的访问根节点的所有孙子节点,以此类推。

广度优先遍历主要是从层级关系出发,一层一层的对树进行遍历。

12.图

1.图的说明

图由顶点和边组成,分为有向图和无向图。

2.图的表示

图一般由两种常用的方式来表示,一种是邻接矩阵(也就是二维数组);另一种是邻接线性表(链表).一般根据图的情况(边的多少),来决定使用哪种表示方式:

  1. 如果边比较多,一般使用邻接矩阵。
  2. 如果边比较少,一般使用邻接线性表。
  3. 由于邻接矩阵会占用大量的存储空间,一般建议使用邻接纯线性表。

3.图的遍历

  1. 深度优先搜索
  2. 广度优先搜索

13.多线程

1.新建的线程什么时候会被关闭

run方法中的代码都执行完毕后,就会被终止。

2.直接调用run方法和start的区别

直接调用run方法,任务会在当前线程上运行,而不是新创建一个线程。

3.使用Runnable,而不直接使用Thread来创建并执行任务的好处

使用Runnable的好处就是把任务和运行任务进行了解耦,更方便复用。

4.yield

让cpu为其它线程临时让出cpu执行时间,并且只能让同优先级及以上线程有执行机会。

5.sleep

暂停执行一段时间,以给其它线程运行机会,不会考虑线程的优先级。会抛出interruptedException异常,如果线程在sleep状态下被调用interrupt方法(也就是终止),就会抛出此异常。

synchronized代码执行中,不会释放对象锁。

6.sleep和yield的区别

  1. sleep方法给其它线程运行机会时不会考虑线程的优先级,而yield只会给同级别或者更高级别以运行机会。
  2. 线程执行sleep方法后会转入阻塞状态,而调用yield方法后,会进入就绪状态。
  3. sleep方法声明抛出InterruptedException异常,而yield没有声明任何异常
  4. sleep方法比yield方法有更好的可移植性。(在操作系统调度方面)

7.wait

让线程让出cpu执行机会,一旦调用了wait方法后,只能通过notify或者notifyAll来唤醒该线程。也会抛出InterruptedException异常。调用wait后线程处于挂起状态。

如果某个线程获得了对象锁,在调用了wait方法后,会释放该对象锁。

同时调用wait之前,该线程必须要获得线程锁,否则会抛出IllegalMonitorStateException异常。

8.wait和sleep的区别

  1. wait只能在同步方法或者同步代码块中被调用,因为需要获取对象锁,否则会抛出IllegalMonitorStateException异常,而sleep可以在任何地方被调用。
  2. wait属于object的方法,而sleepThread的方法
  3. 在同步代码中执行时,sleep不会释放线程锁,而wait会释放线程锁。
  4. 执行wait后,线程进入挂起状态,只能通过notify或者notifyAll才能被唤醒,而sleep被调用后,会进入阻塞状态,睡眠时间一过,就会被自动唤醒。

9.join

join的作用是:使一个线程等待另一个线程的结果后再开始执行。

10.setPriority

使用该方法可以设置线程的优先级。

11:线程池

Executorjava中的一个线程池类。一般我们通过静态方法来创建线程池。也可以通过ThreadPoolExecutor类来创建一个自定义的线程池。

  1. Executors.newFixedThreadPool(int i)

创建固定线程数量的线程池,处于线程池中的线程不会被关闭,除非调用interrupt方法将其终止。

2.Executors.newCachedThreadPool()

此线程池为缓存可伸缩的非常灵活的线程池。当有大量任务需要执行时,该线程池会为任务创建新的线程,可创建线程的数量取决于JVM可创建的最大线程大小。

而当任务执行完毕后,线程处于空闲状态后60s,会将此线程进行回收。

3.Executors.newSingleThreadExecutor()

创建一个单线程的线程池,这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。

4.Executors.newScheduledThreadPool()

创建一个大小无限的线程池,此线程池支持定时或周期性执行任务的需求。

    //执行线程池大小
    ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

    long initialDelay1 = 1;
    long period1 = 1;
    // 从现在开始1秒钟之后,每隔1秒钟执行一次job1
    service.scheduleAtFixedRate(
            new ScheduledExecutorTest("job1"), initialDelay1,
            period1, TimeUnit.SECONDS);

5.Executor.shutdown和shutdown的区别

shutdown调用后,不可以再submit新的task,已经submit的将继续执行。

shutdownNow试图停止当前正执行的task,并返回尚未执行的task的list

6.不带缓冲区的生产者/消费者的示例

1.depositTask代码(存钱的任务)

    public class DepositTask implements Runnable {
    private Acount mAcount;

    public DepositTask(Acount acount) {
        this.mAcount = acount;
    }

    @Override
    public void run() {
        while (true) {
            try {
                mAcount.deposit((int) (Math.random() * 10 + 1));
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

2.WithDrawTask(取钱的任务)

public class WithDrawTask implements Runnable {
    private Acount mAcount;

    public WithDrawTask(Acount acount) {
        this.mAcount = acount;
    }

    @Override
    public void run() {
        mAcount.withDraw((int) (Math.random() * 10 + 1));
    }
}

3.Accout(帐户)

public class Acount {
    private int balance;
    private static Lock lock = new ReentrantLock();
    private static Condition mCondition = lock.newCondition();


    public void deposit(int amount) {
        lock.lock();
        try {
            balance += amount;
            System.out.println("deposit:" + balance);
            mCondition.signalAll();
        } catch (Exception e) {
        } finally {
            lock.unlock();
        }
    }

    public void withDraw(int amount) {
        lock.lock();
        try {
            while (amount > balance) {
                System.out.println("withDraw: wait.....");
                mCondition.await();
            }
            balance -= amount;
            System.out.println("withdraw:" + amount + "======balance:" + balance);
        } catch (Exception e) {
        } finally {
            lock.unlock();
        }
    }
}

4.测试类

public class test {
    private static Acount acount = new Acount();

    public static void main(String[] args) {
        ExecutorService service = Executors.newFixedThreadPool(2);
        service.execute(new DepositTask(acount));
        service.execute(new WithDrawTask(acount));
        service.shutdown();
    }
}

12。 concurrent包

1.BlockingQueue

BlockingQueue(阻塞队列):是一个依赖生产者/消费者模型来设计的,主要通过put(添加)和take(取出)来模拟生产者和消费者。事实上,使用其它方法添加和删除时,当队列为空或者已满的情况下,是会抛出异常的。

ArrayBlockingQueue(数组阻塞队列)

此队列是一个FIFO的有界队列,有界是说明它的大小是有限的,必须给其设置一个值。

DelayQueue(延迟队列)

此队列主要是延迟处理队列中的元素,可以为中的元素设置一个过期时间,当使用take去取数据时,如果过了过期时间,可以马上取出数据,如果还没到过期时间,则等待到达过期时间后才能取出该数据。

在使用此队列时,需要添加的元素实现Delayd接口。

class DelayedElement implements Delayed {
    private final long delay;

    private final long expire;

    public DelayedElement(long delay) {
        this.delay = delay;
        expire = Calendar.getInstance().getTimeInMillis() + delay;
    }

    @Override
    public long getDelay(TimeUnit unit) {
        return expire - Calendar.getInstance().getTimeInMillis();
    }

    @Override
    public int compareTo(Delayed o) {
        return (int) (this.delay - o.getDelay(TimeUnit.MILLISECONDS));
    }

    @Override
    public String toString() {
        return "DelayedElement is " + delay + "\n" + Calendar.getInstance().getTime().toString() + "\n elapsed time is " + getDelay(TimeUnit.DAYS);

    }
}

这样子看起来,好像这个对象并没有做什么其它的操作,只是在判断当前对象是否超时,而没有具体的东西。你可以在构造方法中加入具体的业务对象来与此延迟对象来进行绑定。

LinkedBlockingQueue(链式阻塞队列)

LinkedBlockingQueue是一个FIFO链式结构的队列,可以指定队列的最大值,默认为Integer.maxValue().

PriorityBlockingQueue(优先级阻塞队列)

PriorityBlockingQueue(优先级队列)是一个无界的并发队列。添加到队列中的元素必须实现Comparable接口(让其进行排序)

SynchronousQueue(同步队列)

SynchronousQueue(同步队列):队列中只能有一个元素,当存在一个元素后,添加操作会进入阻塞,此时的操作应该是取出此单个元素,取出元素后,取出的操作就会被阻塞,而等待添加新的元素,依此循环。

blockingDeque(阻塞双端队列接口)

blockingDeque(阻塞双端队列):表示可以从任意一端插入数据或者取出数据。当队列满时,插入操作会进入阻塞,而当队列为空时,取出数据会进入阻塞状态。通过addFirst/addLast以及removeFirst/removeLast.此接口的唯一实现类为LinkedBlockingDeque

LinkedBlockingDeque(链式阻塞双端队列)

由链表组成的双端可读写的阻塞式队列。

2.信号量

信号量可以用来访问共享资源的线程数,线程必须从信号量中获取许可,访问完资源后,这个线程需要把许可返回给信号量。

img

3.死锁以及避免死锁的方法

img

相关文章

  • 记录java一些东西

    1.调用泛型方法 使用.<类型>函数方法的方式调用泛型方法,而此<类型>是可以省略的。 2.泛型类型的定义 定义类...

  • Java 线程和 volatile 解释

    最近开始学习 Java,所以记录一些 Java 的知识点。这篇是一些关于 Java 线程的文章。 Java 支持多...

  • 记录一些东西

    很多事,不适合对任何人说,却可以分享 有些观点,可以作为沉淀,总结过去,警醒未来 有些人,值得记录,但没必要留下姓...

  • java中八大基本数据类型笔记

    一、背景 接触java时间越来越久,一些基本的东西反而提笔忘字,需要反思一下,今天记录一下最基本的java八大基本...

  • 每天记录一些东西

    每天记录一些东西,让时光慢一点走。 比如,记下女儿成长的一个瞬间。 记录家人的一张笑脸。 记下一个感人的故事。 记...

  • 一些 Java 9 新用法

    Java 9 的一些特性 记录一些 java 9 的新用法 1 集合工厂方法 List,Set 和 Map 接口...

  • Java好文收集

    Java日志 Java日志终极指南关于日志记录的一些感想 Spring测试 testing-improvement...

  • Java并发编程学习总结

    关于并发 并发在开发中广泛的应用,非常的重要,最近在读《Java并发编程的艺术》艺术,希望写一些东西来记录和巩固。...

  • java基础汇总

    本遍主要是记录下最近复习java基础的一些情况。 什么是java? java语言是美国Sun公司(Stanford...

  • JVM系列-02-GC-扫盲

    [TOC] 声明 本篇文章是本人阅读《深入理解JVM》和《java虚拟机规范》时的笔记。记录的都是一些概念性的东西...

网友评论

      本文标题:记录java一些东西

      本文链接:https://www.haomeiwen.com/subject/pxpksxtx.html