杂七杂八的java学习笔记

Object

Object是所有类的超类,只有Object没有父类;

注:如果某个数据没有指定明确的类型或者暂时不确定的话,都可以把它置为Object数据类型,可以理解为该类型兼容一切。无论什么样的数据类型都可以使用Object来接受,可以把它当做暂时的容器,等确定了数据类型后再把Object的数据转换成对应的数据类型即可。

封装类赋值注意事项

直接使用Float、Long、Double类赋值的时候,需要在数值后面加上对应的类型标识,即F、L、D。


Java语言三大特性

封装、继承、多态

封装:隐藏对象的属性和实现细节,仅对外提供公共访问方式。

优点:

  1. 提高代码的安全性
  2. 提高代码的复用性
  3. 高内聚:封装细节,便于修改内部代码,提高可维护性
  4. 低耦合:简化外部调用,便于调用者使用,便于拓展和协作

继承:子类可以继承父类的属性和功能,即继承了父类的数据和数据上的操作,又可以增加子类独有的数据和数据上的操作。

优点:代码复用

注:

  1. 子类拥有父类不是private的属性和方法
  2. 子类可以对父类进行拓展

多态:主要体现在Java的重写和重载上面。


构造器

构造方法只能被调用,不能被继承

  1. 如果父类有默认的构造方法(不带参数的方法),子类会自动调用父类该默认构造方法。
  2. 如果父类没有默认构造方法,就要显示的使用super()来调用父类构造方法,且要写在子类构造方法的第一行。
  3. 类中必定有构造方法,若不写,系统自动添加无参构造方法。接口不允许被实例化,所以接口中没有构造方法。
  4. 不能被static、final、synchronized、abstract和native修饰。

抽象类和接口

抽象类

  1. 不能被实例化,需要子类继承它来实例化它的抽象方法。
  2. 抽象方法必须由子类来进行重写。
  3. 只要包含一个抽象方法的类,该类就必须要定义成抽象类,不管是否包含其他方法。
  4. abstract 不能与private、static、final或native并列修饰同一个方法。
  5. abstract不能与final并列修饰同一个类。为什么:final修饰的类不能被重写和继承,而abstract类必须被子类继承。

接口

  1. 接口只能进行方法的声明,不允许提供方法的实现。
  2. 接口中的方法默认是public和abstract的,在接口中可以省略,但是在实现它的类中必须要用public修饰。
  3. 接口中的变量是public static final的。
  4. 如果一个接口不加public修饰,就称为友好接口,可被同一个包中的类使用。
  5. 如果父类实现了某个接口,那么子类也自然实现该接口。
  6. 接口可以被继承。

数组

声明数组方法:

  1. int[] arr;

    arr=new int[size];

  2. int[] arr=new int[size];

  3. int[] arr={1,2,3,4,5};


集合
Collection父接口

代表一组任意类型的对象,无序、无下标、不能重复。

注:一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。

public class Demo {
    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add("宝马");
        collection.add("奔驰");
        collection.add("奥迪");
        collection.add("法拉利");
        System.out.println("长度:"+collection.size());
        System.out.println("-------第1种遍历Collection方式:增强for循环-------");
        for (Object object : collection) {
            String s = (String)object;
            System.out.println(o);
        }
        System.out.println("-------第2种遍历Collection方式:迭代器-------");
        Iterator it = collection.iterator();
        while (it.hasNext()){
            String str = (String)it.next();
            System.out.println(str);
        }
    }
}

List子接口:有序、有下标、元素可以重复。

  • ArrayList:使用数组方式实现,其容量随着元素的增加可以自动扩张,特点是查询效率高,而增加、删除效率低,线程不安全。
  • Vector:Vector和ArrayList的存储特性是一样的,它是线程安全的,查询效率比ArrayList低。
  • LinkedList:基于双向链表来实现的,链表中的每个节点都包含了对前一个和后一个元素的引用。元素的增加和删除操作效率高,查询效率不如ArrayList,也是线程不安全的。

为什么ArrayList查找快、增删慢,LinkedList查找慢,增删快?

ArrayList中的数据在内存中是连续的,成块的,查找的时候直接顺序遍历就可以了。而插入删除的时候,就要把修改的那个节点之后的所有数据都向后或向前移动,所以慢。

LinkedList是一个相互引用的节点组成的双向链表,当把数据插入到该链表某个位置时,该数据就会被组装成一个新的节点,只需改变链表中对应两个节点之间的引用关系,使它们指向新节点,即可完成插入,删除数据时,只需要删除对应节点的引用即可。


泛型

本质是参数化类型,把类型作为参数传递。

泛型类:class A

注:

  1. 泛型只能使用引用类型
  2. 不同泛型类型对象之间不能相互赋值
  3. 使用泛型类声明对象时,必须指定类中使用的泛型的具体实际类型

好处:

  1. 提高代码的重用性
  2. 防止类型转换异常,提高代码的安全性

泛型接口:interface A

泛型方法: 返回值类型


Set子接口

不允许重复元素,也不区分先后顺序,但允许元素是null值

  • HashSet

基于Hash算法实现,其性能比TreeSet好,特点是增加删除元素快

HashSet每次添加新对象时,会使用equals方法,根据散列码来判断是否重复

  • TreeSet

可以把元素自然排序


Map接口

不是继承Collection接口的,Map接口及其实现类主要是存储键值对。

  • HashMap

存储方法为键值对,特点是线程不安全

  • TreeMap

支持自然排序

  • Hashtable

线程安全

遍历map集合方法:

  1. keySet()方法
  2. entrySet()方法

多线程

线程的生命周期:新建、就绪、运行、中断、死亡。

创建线程的方法:
  1. 继承Thread方式创建线程
//1.继承Thread类
public class TestThread01 extends Thread {

    //2.重写run()方法
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我是傻逼------"+i);
        }
    }

    //main()方法,主线程
    public static void main(String[] args) {
        //实例化一个对象
        TestThread01 testThread01 = new TestThread01();
        //3。调用start()方法
        testThread01.start();

        for (int i = 0; i < 200; i++) {
            System.out.println("我是大聪明------"+i);
        }
    }
}
  1. 实现Runnable接口方式创建线程**(推荐)**
//1.实现Runnable接口
public class TestThread03 implements Runnable {

    //2.重写run()方法
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println("我是牛马-------"+i);
        }
    }

    public static void main(String[] args) {

        //3.实例化一个线程对象
        TestThread03 testThread03 = new TestThread03();
        //4.通过Thread对象,代理TestThread03开启线程
        new Thread(testThread03).start();

        for (int i = 0; i < 200; i++) {
            System.out.println("我是帅比-------"+i);
        }
    }
}

注:以上两种方式创建线程,都需要重写run()方法。

  1. 实现Callable接口(了解)

需要重写的是call()方法

终止线程的方法:(通过标识位,停止线程)

步骤:

  1. 线程类中定义一个标识
  2. run方法中使用该标识
  3. 提供对外的方法改变该标识
  4. 调用该改变标识的方法
public class ThreadStop implements Runnable {

    //1.定义一个标识
    private boolean flag = true;

    //2.线程体使用该标识
    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println("Thread is running..."+i++);
        }
    }

    //3.提供改变标识的方法
    public void stop(){
        this.flag = false;
    }

    public static void main(String[] args) {

        ThreadStop threadStop = new ThreadStop();
        new Thread(threadStop).start();

        for (int i = 0; i <= 1000; i++) {
            System.out.println("main---"+i);
            if (i==900){
                //4.调用改变标识的方法
                threadStop.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}
线程休眠

sleep()方法实现倒计时

public class ThreadSleep {
    public static void tenDown() throws InterruptedException {
        int num = 10;
        while(true){
                Thread.sleep(1000);
                System.out.println(num--);
                if (num<=0){
                    break;
                }
        }
    }

    public static void main(String[] args) {
        try {
            tenDown();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
线程礼让

不一定都礼让成功,看cpu心情

public class ThreadYield implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName()+"开始执行");
        Thread.yield();
        System.out.println(Thread.currentThread().getName()+"停止执行");
    }

    public static void main(String[] args) {
        ThreadYield threadYield = new ThreadYield();

        new Thread(threadYield,"A").start();
        new Thread(threadYield,"B").start();
    }
}
线程优先级

范围:1-10

默认:5

获取优先级:getPriority()

设置优先级:setPriority(),在start()前设定

注意:优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用了,最终是看CPU的调度

守护(daemon)线程
  1. 线程分为用户线程和守护线程
  2. 虚拟机必须确保用户线程执行完毕
  3. 虚拟机不用等待守护线程执行完毕
  4. 守护线程:后台记录操作日志、监控内存、垃圾回收等线程

setDaemon()方法设线程为守护线程

public class TestDaemon {
    public static void main(String[] args) {
        God god = new God();
        You you = new You();

        Thread godThread = new Thread(god);
        Thread youThread = new Thread(you);

        godThread.setDaemon(true);
        godThread.start();
        youThread.start();
    }
}

class God implements Runnable{
    @Override
    public void run() {
        while(true){
            System.out.println("上帝一直保佑着你");
        }
    }
}

class You implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 36500; i++) {
            System.out.println("你一直快快乐乐地活着");
        }
        System.out.println("=======Goodbye World=======");
    }
}
死锁

多个线程各自占有一些共享资源,并且互相等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形。某一个同步块同时拥有“两个以上对象的锁”是,就可能会发生“死锁”的问题。

产生死锁的四个必要条件:

  1. 互斥条件:一个资源每次只能被一个进程使用。
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
  3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺。
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
线程同步

方法1:添加synchronized关键字

synchronized方法和synchronized块。

注:对会改变的变量加锁,即需要增删改地对象

(只要涉及到并发,最好给方法添加synchronized关键字)

方法2:使用ReentrantLock实现同步

线程协作

解决生产者/消费者模式

  1. 管程法
  2. 信号灯法
线程池

经常创建和销毁、使用量特别大的资源,比如并发情况下的线程,对性能影响很大

思路:

提前创建好多个线程,放入线程池中,使用时直接获取,使用完放回池中。可以避免频繁创建销毁,实现重复利用。

好处:

  • 提高响应速度(减少了创建新线程的时间)
  • 降低资源消耗(重复利用线程池中线程,不需要每次都创建)
  • 便于线程管理,如corePoolSize:核心池的大小;maximunPoolSize:最大线程数;keepAliveTime:线程没有任务时最多保持多长时间后会终止
public class MyThreadPool {
    public static void main(String[] args) {
        //1.创建服务,创建线程池
        ExecutorService service = Executors.newFixedThreadPool(10);
        //2.执行
        service.execute(new MyPool());
        service.execute(new MyPool());
        service.execute(new MyPool());
        service.execute(new MyPool());
        //3.关闭连接
        service.shutdown();
    }
}

class MyPool implements Runnable {
    @Override
    public void run() {
        System.out.println(Thread.currentThread().getName());
    }
}
产生死锁的四个必要条件
  1. 互斥条件:该资源任意一个时刻只由一个线程占用
  2. 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
  3. 不剥夺条件:线程已获得的资源在未使用完之前不能被其他线程强行剥夺,只有自己使用完毕后才释放资源
  4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系

Lambda表达式

Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中)。

使用 Lambda 表达式可以使代码变的更加简洁紧凑。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值