记录java一些东西

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
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,179评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,229评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,032评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,533评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,531评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,539评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,916评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,574评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,813评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,568评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,654评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,354评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,937评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,918评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,152评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,852评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,378评论 2 342

推荐阅读更多精彩内容