狂神Java基础学习笔记

JavaSE

多态

  1. 父类引用子类的对象
  2. 把子类转化为父类,向上转型
  3. 把父类转化为子类。向下转型:强制转换
  4. 方便方法的调用,减少重复的代码,简洁!

抽象类

  1. abstract关键字在类上,那么这个类就是抽象类
  2. JAVA中是单继承机制,但是接口可以实现多继承
  3. abstract 如果修饰方法,那么这个方法就是抽象方法
  4. 如果子类继承了抽象类,那么他就必须去实现父类的抽象方法
  5. 抽象类的所有方法,继承了的他的子类就必须去实现他们的抽象方法
  6. 除非子类也是抽象的,那么抽象方法就由子子类实现

抽象类的特点

  1. 不能new这个抽象类,只能靠子类去实现它
  2. 抽象类中可以写普通方法
  3. 抽象方法一顶要写到抽象类中

接口

接口的作用

  1. 接口是一个约束
  2. 接口可以定义一些方法,让不同的人实现
  3. 接口中的方法都是public abstract,都是抽象的
  4. 接口中的常量都是 public static final
  5. 接口不能直接被实例化,因为接口中没有构造方法
  6. 可以实现多个接口,implements可以实现多个接口
  7. 实现接口必须要重写接口中的方法

内部类

  1. 通过外部类可以来实例化一个内部类
  2. 内部类可以获得外部类的私有(private)属性
  3. 在方法里面写class类,这个类叫做局部内部类
  4. 一个java类中可以有多个class,但是只能有一个public class类
  5. 可以直接new一个匿名内部类,不需要名字,直接.方法就行了:new Demo01.a();

异常

Error和Exception的区别

  1. Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这种异常时,java虚拟机(JVM)一般会选择终止线程。
  2. Exception通常情况下是可以被程序处理的,并且在程序中应该可以竟可能的去处理这些异常。

异常处理的五个关键字

  1. try
  2. catch
  3. finally
  4. throw
  5. throws

五个关键字的用法

  1. try:里面放置待监控的代码块,监控其中的代码
  2. catch:捕获try中的异常
  3. finally:不管程序是否异常,都会执行finally里面的代码,用来处理善后工作,比如关闭资源管理等等
  4. throw:在方法中主动抛出一个异常,一般用在方法体内
  5. throws:假设在方法中,处理不了这个异常,那么就要用throws在方法上抛出,一般要和try-catch组合使用

异常实际应用中的经验总结

  1. 处理运行时异常时,采用逻辑去合理规避同时辅助try-catch处理
  2. 在多重catch块后面,可以加一个catch(Exception)来处理可能被遗漏的异常
  3. 对于不确定的代码,也可以加上try-catch,处理潜在的异常
  4. 尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
  5. 具体如何处理异常,要根据不同的业务需求和异常类型去决定
  6. 精良添加finally语句块去释放占用的资源

多线程

重点掌握

  1. 线程实现
  2. 线程同步

多线程核心概念

  1. 线程就是独立的执行路径
  2. 在程序运行时,及时没有自己创建的线程,后台也会有多个线程,比如主线程gc线程等等
  3. main()称之为主线程,为系统的入口,用于执行整个程序
  4. 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为的干预的
  5. 对同一份资源进行操作是,会存在资源抢夺的问题,需要加入并发控制
  6. 线程会带来额外的开销,如cpu调度时间,并发控制开销
  7. 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致

多线程的创建方式

  1. 继承Thread类,重写run()方法,调用start开启线程

  2. 创建一个线程声明为Runnable接口,实现run()方法,创建线程的对象,调用start()方法来启动线程

  3. 实现callable接口,创建执行服务、提交执行、获取结果、关闭服务

    public class ThreadNew {
        public static void main(String[] args) {
            //启动
            new MyThread1().start();
    
            new Thread(new MyThread2()).start();
    
            FutureTask<Integer> futureTask = new FutureTask<Integer>(new MyThread3());
            new Thread(futureTask).start();
    
            try {
                Integer integer = futureTask.get();
                System.out.println(integer);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
        }
    }
    
    //1.继承Thread类
    class MyThread1 extends Thread{
        @Override
        public void run() {
            System.out.println("MyThread1");
        }
    }
    
    //2.实现Runnable接口
    class MyThread2 implements Runnable{
    
        @Override
        public void run() {
            System.out.println("MyThread2");
        }
    }
    
    //3.实现callable接口
    class MyThread3 implements Callable{
    
        @Override
        public Object call() throws Exception {
            System.out.println("MyThread3");
            return 100;
        }
    }
    

注意

  1. 线程开启不一定立即执行,由cpu调度安排

对比 继承Thread类 和 实现Runnable接口

继承Thread类
  • 子类继承Thread类具备多线程能力
  • 启动线程:子类对象.start()
  • 不建议使用:避免oop单继承的局限性
实现Runnable接口
  • 实现接口Runnable具备多线程能力
  • 启动线程:传入目标对象+Thread对象.start()
  • 推荐使用:避免单继承的局限性,灵活方便,方便同一个线程被多个线程使用

Callable的好处

  1. 可以定义返回值
  2. 可以抛出异常
  3. 但是实现比较复杂

静态代理模式

静态代理模式总结

  1. 真实对象和代理对象都要实现同一个接口
  2. 代理对象要代理真实角色

静态代理模式的好处

  1. 代理对象可以做很多真实对象做不了的事情
  2. 真实对象专注做自己的事情

Lambda表达式

函数式接口的定义

​ 任何接口,如果只包含了唯一一个抽象方法,那么这就是一个函数式接口。

Lambda表达式的使用前提

对于函数式接口,我们可以通过Lambda表达式来创建该接口的对象

like = ()->{
    System.out.println("I like lambda5");
};
like.lambda();

为什么要使用Lambda表达式

  • 避免匿名内部类定义过多
  • 可以让你的代码看起来更简洁
  • 去掉一堆没有意义的代码,只留下核心的逻辑

Lambda表达式总结

  • lambda表达式只能有一行代码的情况下才能简化为一行,如果有多行代码,那么就要用代码块包裹
  • 前提是接口为函数式接口,即接口中只有一个方法
  • 多个参数也可以去掉参数类型,要去掉就一起去掉,必须加上()
  • 不同的参数类型也可以
  • 因为Runnable接口(多线程实现方法2)中只有一个run()方法,所有很适合用lambda表达式

线程Thread类的方法

线程停止

  1. 建议让线程正常停止—>利用次数,不建议死循环
  2. 建议使用标志位flag—>设置一个标志位flag
  3. 不要使用stop或者destory等过时的,或者JDK不建议使用的方法

线程休眠

  • sleep()指定当前线程阻塞的毫秒数
  • sleep存在异常InterruptedException
  • sleep时间达到后线程进入就绪状态
  • sleep可以模拟网络延时,倒计时等
  • 每一个对象都有一个锁,sleep不会释放锁

线程礼让

  • 礼让线程,让当前正在执行的线程暂停,但不阻塞
  • 将线程从运行状态转化为就绪状态
  • 让CPU重新调度,礼让不一定成功,看CPU心情

线程Join

  • Join合并线程,待次线程执行完成后,再执行其他的线程,其他线程阻塞
  • 可以想象为插队

线程状态

​ 线程中断或者结束,一旦进入死亡状态,就不能再次启动(线程只能启动一次)

thread.getState()

​ 可以用上面这个方法观测线程的状态

线程优先级

​ 优先级低只是一味这获得调度的概率第,并不是优先级低就不会被调用了,这都看CPU的心情

守护线程

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

线程死锁

产生死锁的四个必要条间

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

synchronized 和 Lock 的对比

  • Lock是显示锁(手动开启和关闭锁,别忘记关闭锁)synchronized 是隐式锁,出了作用域自动释放

  • Lock只有代码块锁,synchronized 有代码块锁和方法锁

  • 使用Lock锁,JVM将花费较少的时间来调整线程,性能更好。并且具有更好的拓展性(提供更多的子类)

  • 优先使用顺序:

    Lock > 同步代码块(已经进入了方法体,分配了相应的资源) > 同步方法(在方法体之外)

集合

Collection常用方法

  1. size():判断集合长度

  2. add():添加元素

  3. addAll():另一个集合添加到当前的集合中

  4. clear():把集合中的元素清空

  5. isEmpty():判断集合是否为空

  6. remove():删除数组中的元素,可以又返回值,删除成功返回true,失败返回false

  7. removeAll():删除当前集合所包含集合中的所有元素

  8. contains():判断当前集合是否有当前元素

    ​ 判断依据:根据当前元素所在的类中的equals()方法来进行判断

  9. containsAll(Collections c):当前集合中的元素是否包含形参c中的元素

  10. hashCode():获得集合的地址值

  11. equals():比较级和中的所有元素是否相同

  12. retainAll():求两个集合的交集,并返还给原集合

  13. toArray();把集合转化为数组对象

如果存的是自定义类,要求重写equals()方法

两种for循环的比较

public static void main(String[] args) {
    Collection c = new ArrayList();
    c.add(123);
    c.add("aa");
    c.add(new Person("kele", 20));
    c.add(new Person("kekou",19));
    
    Object[] o = c.toArray();
    //普通for循环
    for (int i = 0; i < o.length; i++) {
        System.out.println(o[i]);
    }
    //JDK5.0之后加强的for循环
    for (Object o1 : o) {
        System.out.println(o1);
    }
}
	注意输出的值是循环内定义的值
格式: for(类型 参数名 : 数组或集合类){ }
	类型必需与数组或集合类的类型相同,
	参数的值是动态的,所有数组或集合类的每一个值。

List接口的特点

  1. 存储和读取的顺序一致
  2. 有索引
  3. 有序的,元素可以重复
特有的方法
  1. void add(int index, Object o):添加
  2. object get(int index):获取
  3. Object remove(int index):删除,返回值是删除的元素
  4. Object set(int index, Object o):更新设置,返回值是该位置之前的元素
  5. indexOf(Object o):返回o在集合中第一次出现的下标,没有就返回-1
  6. lastIndexOf((Object o):返回o在集合中最后一次出现的下标,没有就返回-1
  7. subList(int fromIndex, int toIndex):截取一个集合,含头不含尾

LinkedList特有的方法

  1. addFirst():把元素添加到链表的第一个
  2. getFirst():获取链表的第一个元素
  3. removeFirst():删除链表的第一个元素,有返回值,返回值为这个删除的元素
  4. getList()
  5. removeList()

getFirst()方法和栈相似,每次把元素添加到链表的最前面,所以最先添加的元素在最后面

public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.addFirst("aa");
        list.addFirst("bb");
        list.addFirst("cc");
        list.addFirst("dd");
        list.addLast("ee");
        System.out.println(list.getFirst());
        System.out.println(list.getLast());
        System.out.println("----------");
        for (Object o : list) {
            System.out.println(o);
        }
    }

运行结果:

在这里插入图片描述

HashSet的特点

  1. 无序
  2. 唯一,元素不可重复

在HashSet实例化对象后添加对象时,首先调用对象所在类的hashCode()方法,计算此对象的哈希值。这个哈希值就决定了这个对象的Set集合中的位置,如果这个位置没有对象进行存储,则这个对象就存储到这个位置。如果这个位置有对象了,在通过equals方法来进行比较,如果equals方法比较结果一样,就不在进行存储了。如果equals方法不一样,就在下一个位置存储。

​ 一般情况下,我们会保证hashcode和equals一致

​ 重写hashcode方法和equals方法上。

LinkedHashSet

​ LinkedHashSet:使用链表来维护一个集合

​ 我们遍历元素的时候是按照元素添加的顺序进行的

​ LinkedHashSet插入的性能略低于HashSet,但是迭代的时候性能会好一些。

TreeSet

  1. 默认会把TreeSet里的元素排序,存储的比如String或者包装类,他都按自然排序
  2. 存储的对象应该属于同一类
  3. 存储对象是自定义对象时
    1. 让对象自身具有可比性,对象所在的类需要实现Comparable接口,如果不实现,会出现classCastExcpetion异常
    2. 容器本身制定比较规则
实现Comparable中的compareTo()方法
@Override
public int compareTo(Object o) {
    return 1;
}
//比较器
@Override
public int compareTo(Object o1, Object o2) {
    Person p1 = (Person)o1;
    Person p2 = (Person)o2;
    int i = p1.getAge().compaterTo(p2.getAge());
    if(i == 0){
        return p1.getName().compareTo(p2.getName());
    }
    return i;
}

注意:

  1. 返回值为0,代表所有元素都一样,只会存储第一个数据
  2. 返回值为正整数,按顺序存取
  3. 返回值为负整数,逆序存取

工具类

用的时候查API,不需要死记

collections
  • max():最大值
  • min():最小值
  • reverse():集合逆序
  • sort():排序
Arrays
  • binarySearch():使用二分查找搜索指定的数组
  • asList():返回一个受指定的数组支持的固定大小的列表

小结


Collection:  add(Object obj)  addAll(Collection c) size() clrear() isEmpty()
		remove(Object obj) removeAll(Collection c) retainAll(Collection c)
		contains(Object obj) containsAll(Collection c) hashCode()
		iterator(), toArray()
	

	-->List:有序,可以重复存储元素
		特有的: add(int index, Object obj) remove(int index)
		       Object set(int index, Object obj)
			   Object get(int index)   int indexOf(Object obj)
			   int lastIndexOf(Object obj)   List subList(int from, int to)
		
		-->ArrayList:内部是一个数组结构,不同步,代替了Vector,查询快
		-->LinkedList:内部数据结构是一个链表, 不同步,增删快
		-->Vector:内部数据结构也是数组,同步的。增删查都慢
	
	
	-->Set:无序,元素唯一
		Set接口与Collection接口中的方法一致
		
		-->HashSet:内部数据结构是哈希表,不同步。
				怎么保证存储的元素唯一呢?
				通过对象的hashCode和equals方法来确定的
				如果对象的hashCode不同,就不用再判断equals方法了,直接存储到集合中
				如果对象的hashCode相同,就需要根据equals方法来进行判断
							如果结果为true,视为相同,不再进行存储
							如果为false,视为不同,就进行存储(不建议)
							
				注意:如果元素存储到hashSet中,必须要覆盖hashCode和equals方法
					尽量这两个方法保持一致
				
			-->LinkedHashSet:是其子类,当我们遍历集合的时候,是按照我们添加顺序进行的
					频繁的遍历,但是增删比较少,可以选择这种集合
		-->TreeSet:可以对元素进行排序,是不同的
				判断元素唯一性的方式:就是根据比较方法返回的结构,0(相同), 不存储
				排序的方式?
				1.元素自身具有比较的功能,实现Comparable接口,重写compareTo方法
				2.元素自身不具有比较功能,没有实现Comparable接口,这个时候怎么办呢?
					定义一个类,实现Comparator接口,重写compare方法
					把这个类创建的对象作为参数,通过构造函数传递给TreSet集合

Map: 一次添加一对元素,    Collectio一次添加一次元素
	Map也成为双列集合,    Collection也成为单列集合
	Map中key必须唯一
	
	put(Object key, Object value)  remove(Object key) clear(), size()
	isEmpty()  Object get(Object key)   boolean containsKey(Object key)
	boolean containsValue(Object value)
	
	循环方式?
	1. keySet  -->得到key的集合,循环得到每一个key,通过get(key),获取value
	
	2.entrySet -->得到key和value整体的一个Map.Entry集合,循环得到每一个Map.Entry对象
				通过调用getKey()和getValue(),获取key和value
	
	
	-->HashMap:内部数据结构是哈希表,不同步。允许null作为key或者value
		
		-->LinkedHashMap:是其子类,可以按照添加进map的顺序进行遍历
		
	-->TreeMap:内部数据结构是二叉树,是不同步的。可以对key进行排序
	
	-->HashTable:很少用
		-->Properties:根据IO来一起使用

泛型

泛型:jdk1.5版本之后出现的一种安全机制

泛型擦除技术:是给编译器使用,用于编译期,确保了类型的安全运行,运行期间,.class文件中是没有泛型的。

为什么要有泛型擦除技术?为了兼容运行的类加载器。

泛型补偿:在获取集合元素时,不用再做类型强转了。这既是泛型补偿

Collection<? extends Person>只能存储Person或者Person的子类。

Collection<? supper Person>只能存储Person或者Person的父类。

泛型的好处

  1. 将运行期的类型转换异常转移到了编译器
  2. 避免了强制转换的麻烦

泛型的用处

  • 参数化类型,将具体的类型参数化

自定义泛型

  • 泛型可以用在类上
  • 泛型还可以用在方法上
  • 还以用在返回值上
  • 当方法是静态的,不能访问类上定义的泛型,如果静态方法要使用这个泛型,那么就只能把泛型定义在方法上。

IO流

File类

  • File(String pathname):可以把一个存在或者不存在的文件或者文件目录封装成一个对象
  • File(String parent, String child):
  • File(File parent, String child):
File类的方法
  • 创建删除
    • createNewFile():指定的文件不存在,创建文件并返回true,否则返回false
    • mkdir():创建文件夹
    • mkdirs():创建多级的文件夹
    • delete():删除单个文件或者文件夹,如果文件夹里有文件,无法删除返回false
  • 判断
    • exists():判断文件或者文件夹是否存在
    • isDirectory():判断文件是不是一个文件夹
    • isFile():判断文件对象是不是一个文件
    • isAbsolute():判断当前路径是不是绝对路径
    • isHidden():判断文件是否隐藏
  • 获取
    • getAbsolutePath():获得文件的绝对路径:返回路径字符串
    • getParentFile():获取当前路径的父路径:以文件对象的形式返回
    • getParent():获取当前路径的父路径,以字符串形式返回
    • getPath():获取当前路径
    • getName():获取当前文件或者文件夹名称
    • lastModfied():获取文件最后修改时间
    • length():获取文件长度
    • getTotalSpace():获取文件占用分区总大小
    • rename():给文件重命名
  • 文件目录
    • list():以字符串形式返回当前路径下的所有文件和文件夹
    • listFiles():以File对象形式返回当前路径下的所有文件和文件夹
File类的递归

打印文件夹和文件名称

public static void showList(File file) {
        if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File file1 : files) {
                if(file1.isFile()){
                    System.out.println("文件:" + file1.getName());
                }else if(file1.isDirectory()){
                    showList(file1);
                }
            }
        }
        System.out.println("文件夹:" + file.getName());
    }

删除文件夹内的所有文件和文件夹

public static void remove(File file){
        if (file.isDirectory()){
            File[] files = file.listFiles();
            for (File f : files) {
                if(f.isFile()){
                    f.delete();
                }else if(f.isDirectory()){
                    remove(f);
                }
            }
        }
        file.delete();
    }

字符流

概述

单个的读取字符,只能读文本数据

装饰者设计模式
  • 对原有类进行了功能增强
  • 他与继承有什么不同
    • 继承:
      • 被增强的对象固定
      • 被增强的内容也是固定的
    • 装饰者模式
      • 被增强的对象是可以切换的
      • 被增强的内容也是固定的
    • 动态代理模式
      • 被增强的对象可以切换
      • 被增强的内容也可以切换
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值