Java学习笔记-Java基础

2021/6/6 14:20:53

本文主要是介绍Java学习笔记-Java基础,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

Java基础

多态
概念:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。
特点
1. 要有继承关系
2. 要有方法重写
3. 要有父类引用指向子类对象
成员变量:编译看左边(父类),运行看左边(父类)
成员方法:编译看左边(父类),运行看右边(子类)。动态绑定
静态方法:编译看左边(父类),运行看左边(父类)。静态和类相关,算不上重写
父类引用指向子类对象就是向上转型,还有向下转型:Cat c = (Cat) a;
关键字:instanceof 判断前边的引用是否是后边的数据类型
多态的好处:提高了代码的维护性(继承保证)
提高了代码的扩展性(由多态保证)。当作参数使用的时候最好,因为扩展性强。
多态的弊端:不能使用子类特有的属性和行为

抽象类、方法
概念:当无法描述一个方法时定义为抽象,加上关键字abstract:
抽象类:abstract class 类名{}
抽象方法:public abstract void eat{}
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或接口,抽象类不能实例化。
若要实例化抽象类;按照多态的方式,由具体的子类实例化。其实这也是多态的一种,抽象类多态。
抽象类的子类要么是抽象类,要么重写抽象类的所有抽象方法。
若没有定义抽象方法却定义了抽象类,其目的是不让其他类创建本类对象,交给子类完成。
Abstract不能与static共存:被abstract修饰的方法没有方法体,被static修饰的可以用类名.调用,但是类名.调用抽象方法是 没有意义的。
Abstract不能与final共存:被abstract修饰的方法强制子类重写,被final修饰的不让子类重写,所以他俩是矛盾。
Abstract不能与private共存:被abstract修饰的是为了让子类看到并强制重写,被private修饰的不让子类访问,所以他俩矛盾

接口interface
概念:对外提供规则的都是接口
特点
1. 接口用关键字interface表示:interface 接口名{}
2. 类实现接口用implements表示:class 类名 implements 接口名{}
3. 接口不能实例化:按照多态的方式来实例化
4. 接口的子类可以是抽象类,但是意义不大;可以是具体类,要重写接口中的所有抽象方法
成员变量:只能是常量,并且是静态的并公共的。默认修饰符:public static final
构造放法;接口没有构造方法
成员方法:只能是抽象方法

类与类、类与接口、接口与接口的关系:
类与类:继承关系,只能单继承,可以多层继承
类与接口:实现关系,可以单实现,也可以多实现;还可以在继承一个类的同时实现多个接口
接口与接口:继承关系,可以单继承,也可以多继承

抽象类与接口的区别
1. 成员区别:
抽象类:成员变量:可以变量,也可以常量
构造方法:有
成员方法:可以抽象也可以非抽象
接口:成员变量:只可以常量
成员方法:只可以抽象
2. 关系区别:
类与类:继承、单继承
类与接口:实现,单继承,多实现
接口与接口:继承,单继承,多继承
抽象类:被继承体现的是:”is a”的关系。抽象类中定义的是该继承体系的共性功能。
接口类:被实现体现的是;”like a”的关系。接口中定义的是该继承体系的扩展功能

局部内部类
只能在其所在的方法中访问。局部内部类访问局部变量必须用final修饰

匿名内部类
就是内部类的简化写法。(写在方法里)
前提:存在一个类或接口。这里的类可以是具体类也可以是抽象类
格式:new 类名或者接口名(){重写方法;}
本质:是一个继承了该类或者实现了该接口的子类匿名对象

静态Static
静态是随着类的加载而加载,this是随着对象的创建而存在;静态比对象优先存在;
This调用本类成员变量,super调用父类成员变量

tring StringBuffer和StringBuilder的区别
StringBuffer是jdk1.0版本的,是线程安全的,效率低
StringBuilder是jdk1.5版本的,是线程不安全的,效率高
String是一个不可变的字符序列

JDK5新特性
自动装箱:把基本类型转换为包装类类型
自动拆箱:把包装类类型转换为基本类型
Integer ii = 100;//自动装箱
Ii + = 200;//自动拆箱
-128到127是byte的取值范围,如果在这个取值范围内,自动装箱就不会新创建对象,而是从常量池中获取,如果超过 了byte取值范围就会再创建新的对象

正则表达式
正则表达式:是指一个用来描述或者匹配一系列符合某个语法规则的字符串的单个字符串。其实就是一个规则。有自己特殊的应用
作用:比如注册邮箱,邮箱有用户名和密码,一般会对其限制长度,这个限制长度的事情就是正则表达式做的

集合框架
集合的由来:
数组长度是固定,当添加的元素超过了数组长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加
数组和集合的区别:
区别1:数组既可以存储基本数据类型(存储值),又可以存储引用数据类型(存储地址)
集合只能存储引用数据类型
区别2:数组长度是固定的,不能自动增长
集合的长度是可变的,可以根据元素的增加而增长
数组和集合什么时候用:
1.如果元素个数是固定的推荐用数组
2.如果元素个数不是固定的推荐用集合

在这里插入图片描述
List的三个子类的特点
ArrayList:底层数据结构是数组,查询快,增删慢;线程不安全,效率高
Vector:底层数据结构是数组,查询快,增删慢;线程安全,效率低
Vector相对ArryList查询慢(线程安全的)
Vector相对LinkList增删慢(数据结构)
LinkedList:底层数据结构是链表,查询慢,增删快;线程不安全,效率高
查询多用ArryList
增删多用LinkedList
如果都多用ArrayList

迭代器原理
Collection c = new ArryList();父类引用指向子类对象
Iterator it = c.iterator();获取迭代器
//ListIterator list = list.listIterator;获取迭代器(ListIterator特有)
迭代器原理:迭代器是对集合进行遍历,而每一个集合内部的存储结构都是不同的,所以每一个集合存和取都是不一样,那么需要在每一个类中定义hasNext()和next()方法,第二,代码有底层内部实现,使用者不用管怎么实现的,会用即可
并发修改异常:遍历集合的同时修改

数据结构之数组和链表
A. 数组:查询快修改也快;增删慢
B. 链表:查询慢修改野蛮;增删快

栈和队列数据结构
栈:先进后出
队列:先进先出
泛型概述
基本在类的旁边加<>,<>中放的必须是引用数据类型;前后的泛型必须一致,或者后面的泛型可以省略不写
好处:提高安全性,省去强转的麻烦
静态方法必须声明自己的泛型

HashSet如何保证元素唯一性的原理
1.HashSet原理:
我们使用Set集合都是需要去掉重复元素的,如果存储的时候逐个equals()比较,效率较低,哈希算法提高了去重复的效率,降低了使用equals()方法的次数
当HashSet调用add()方法存储对象的时候,先调用对象的hashcode()方法得到一个哈希值,然后在集合中查找是否有哈希值相同的对象
如果没有哈希值相同的对象就直接存入集合
如果有哈希值相同的对象逐个进行equals()比较,比较结果为false就存入,true则不存
2.将自定义类的对象存入HashSet去重复
类中必须重写hashCode()和equals()方法
HashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)
Equals:属性相同返回true,属性不同返回flase,返回flase的时候存储

LinkedHashSet
底层是链表实现的,是Set集合中唯一一个能保证怎么存就怎么取的集合对象
因为是HashSet的子类,所以也是保证元素唯一的,与HashSet的原理一样

TreeSet保证元素唯一和自然排序
TreeSet集合是用来对元素进行排序的,同样也可以保证元素的唯一
需要重写compareTo方法
当compareTo方法返回0时,集合中只有一个元素
当compareTo方法返回正数的时候集合会怎么存就怎么取
当compareTo方法返回负数时,集合会倒叙存储
TreeSet底层时二叉树,两个叉,小的存储在左边(负数),大的存储在右边(正数),相等就不存在(0)

TreeSet原理

  1. 特点
    TreeSet是用来排序的,可以指定一个顺序,对象存入之后会按照指定的顺序排列
  2. 使用方式
    a. 自然顺序(Comparable)
    TreeSet类的add()方法会把存入的对象提升为Comparable类型
    调用对象的comparableTo方法和集合中的对象比较
    根据compareTo()方法返回的结果进行存储
    b. 比较器顺序(comparator)
    创建TreeSet的时候可以指定一个comparator
    如果传入了comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
    Add()方法内部会自动调用comparator接口中compara()方法排序
    调用的对象时compare方法的第一个参数,集合中的对象是compare方法的第二个参数
    c. 两种方式的区别
    TreeSet构造函数什么都不传,默认按照类中comparable中的顺序
    TreeSet如果传入comparator,就有限按照comparator

Map
双列集合
HashMap:底层是哈希算法,针对键
LinkedHashMap:底层是链表,针对键
TreeMap:底层是二叉树算法,针对键
开发中HashMap比较多

Map集合遍历
For(Map.Entry<String, Integer> en : map.entrySet()){ //键值对对象
System.out.println(en.getKey() + “=” + en.getValue());
}

HashMap和Hashtable的区别:
共同点:
底层都是哈希算法,都是双列集合
区别:

  1. HashMap是线程不安全的,效率高,DK1.2版本
    Hashtable是线程安全的,效率低,JDK1.0版本的
  2. HashMap可以存储null键和null值
    Hashtable不可以存储null键和null值

Collections中的常见方法
Public static void sort (List<?> list) //排序
Public static int binarySearch (List<?> list, T key) //二分查找法(有序集合)
Public static T max (Collection<?> coll) //根据默认排序结果获取集合中的最大值
Public static void reverse (List<?> list) //反转集合
Public static void shuffle(List<?> list) //随机置换

Final、finally、finalize的区别
Final可以修饰类,不能被继承;修饰方法,不能被重写;修饰变量,只能赋值一次
Finally是try语句的一个语句体,不能单独使用,用来释放资源
Finalize是一个方法,当垃圾回收器不存在对该对象的更多引用时,由垃圾回收器调用此方法

如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问实在return前还是return后
会执行。在return之后

IO流Close方法和flush方法的区别
Close方法:具备刷新功能,在关闭之前,就会刷新一次缓冲区,将缓冲区的字节全部刷新到文件上,再关闭,close方法刷完之后就不能写了
Flush方法:具备刷新功能,刷完之后还能继续写

字节流与字符流。
字节流:file.inputStream;file.outputStream
字符流:file.read;file.write(只能拷贝纯文本,一般不推荐拷贝,需要将字节转为字符再将字符转为字节)
只读或只写的时候用字符流。读取时是按照字符的大小读取的,不会出现半个中文

装饰类设计模式

  1. 获取被装饰类的引用
  2. 在构造方法中传入被装饰类对象
  3. 对原有功能进行升级
    好处:耦合性不强,被装饰类的变化与装饰类的变化无关
    指定码表读写字符
    BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(“utf-8.txt”), “utf-8”); //更高效的读
    BufferedWriter bw = new BufferedWriter(new outputStreamWriter(new FileoutputStream(“gdk.txt”), “gdk”); //更高效的写

递归
自己调用自己
递归的弊端:不能调用次数过多,容易导致内存溢出
递归的好处:不用知道循环次数
构造方法不能递归调用
递归调用是否必须有返回值?
不一定(可以有,也可以没有)

Io序列流
序列流可以把多个字节输入流整合成一个,将从被整合的第一个流开始读,读完一个之后继续读第二个,以此类推
序列流整合两个:SequenceInputStream sis = new SequenceInputStream(fis1,fis2)
序列流整合多个:将流对象添加到集合Vector中;创建枚举

  1. Vector v = new Vector<>;
  2. V.add(fis1);
  3. V.add(fis2);
  4. V.add(fis3);
  5. Enumeration en = v.elements();
  6. SequenceInputStream sis = new SequenceInputStream(en)
    sis关闭时会将构造返回发传入的流对象也都关闭

IO流(内存输出流)
该输出流可以向内存中写入数据,写出之后可以一次性获取出所有数据
使用方式:1.创建对象:new ByteArrayOutputStream()
2.写出数据:write(int),write(byte[])
3.获取数据:toByteArray()

IO流(对象操作流)
该流可以将一个对象写出,或者读取一个对象到程序中。也就是执行了序列化和反序列化操作。对象需要实现Seralizable(public class person implements Seralizable)
使用方式:new objectOutputStream(outputStream),writeObject
读档:new objectInputStream(),readObject
对象操作流优化:将对象存储在集合中写出
读取:ArrayList list = (ArrayList)ois.readObject();
For(Person p : list){}

IO流(数据输入输出流)
DataIuputStream,DataOutputStream可以按照基本数据类型大小读写数据
例如按Long大小写出一个数字,写出时该数据占8字节,读取的时候也可以按照Long类型读取,一次读取8个字节
使用方式:DataOutputStream(OutputStream),writeInt(),writeLong()

IO流(标准输入输出流)
System.in是InputStream,标准输入流,默认可以从键盘输入读取数据
System.out是PrintStream,标准输出流,默认可以向Console中输出字符和字节数据

Properties的概述和作为Map的作用
Properties类表示了一个持久的属性集
Propertis可保存在流中或从流中加载
属性列表中没个键及其对应值都是一个字符串
Propertis的特殊功能:
Public Object setProperty(String key, String value)
Public String getProperty(String key)
Public Enmerator stringPropertyNames()

Load():prop.load(new FileInputStream(“xxx.properties”));
Store():prop.store(new FileOuputStream(“xxx.properties”),”liebiaomiaoshu”)

多线程
1. 什么是线程
线程是程序执行的一条路径,一个进程可以包含多条线程
多线程并发执行可以提高程序的效率,可以同时完成多项工作
多线程并行与并发的区别
并行就是两个任务同时运行,就是甲任务进行的同时,乙任务也在进行。(需要多核CPU)
并发是值两个任务都请求运行,而处理器只能接受一个任务,就把两个任务安排轮流进行,由于时间间隔较短,使人感觉两个任务都在运行

Java程序运行原理:
Java命令会启动java虚拟机,启动JVM,等于启动了一个应用程序,也就是启动了一个进程,该进程会自动启动一个“主线程”,然后主线程去调用某个类的 main 方法

JVM启动是多线程吗:
JVM启动至少启动了垃圾回收线程和主线程,所以是多线程的
使用多线程
实现方式一

  1. 继承Thread:class MyThread extends Thread{
  2. 重写run方法:public void run(){
  3. 将要执行的代码写在run方法中:
  4. 在主线程实例化线程子类对象:MyThread mt = new MyThread();
  5. 开启线程:mt.start();
    实现方式二
    1 定义一个类实现Runnable
    2.重写run方法
    3 将要执行的代码写在run方法中
    4 在主线程实例化Runnable子类对象:MyRunnable mb = new MyRunnable();
    5.将其当作参数传递给Thread构造函数:Thread t = new Thread(mb);
    6 开启线程:t.start();
    两种方式的区别:
    继承Thread
    好处:可以直接使用Thread类中的方法,代码简单
    弊端:如果已经有了父类,就不能用这两种方法
    实现Runnable接口
    好处:即使自己定义的线程类有了父类也没关系,因为有了父类也可以实现接口,而且接口是可以多实现的
    弊端:不能直接使用Thread中的方法,需要先获取线程对象后,才能得到Thread的方法,代码复杂
    线程休眠
    Thread.sleep(1000)
    守护线程
    SetDaemon(true),设置一个线程为守护线程,该线程不会单独执行,当其他非守护线程都执行结束后,自动退出
    加入线程
    Join(),当前线程暂停,等待指定的线程结束后,当前线程再继续
    Join(int),可以等待指定的线程执行结束后,当前线程再继续

单例设计模式:保证类在内存中只有一个对象
//饿汉式
Class Singleton{

  1. 私有构造方法,其他类不能访问该构造方法了
    Private Singleton(){}
  2. 创建本类对象
    Private static Singleton s = new Singleton();
  3. 对外提供公共的访问方法
    Public static Singleton getInstance(){
    Return s;
    }
    //懒汉式,单例的延迟加载模式
    Class Singleton{
    1.私有构造方法,其他类不能访问该构造方法了
    Private Singleton(){}
    2.声明一个引用
    Private static Singleton s;
    3.对外提供公共的访问方法
    Public static Singleton getInstance(){
    If(s == null){
    S = new Singleton();
    }
    Return s;
    }
    饿汉式与懒汉式的区别:
    1 饿汉式是空间换时间,懒汉是时间换空间
    2 在多线程访问时,饿汉式不会创建多个对象,懒汉式有可能创建多个对象

Timer类(计时器)
在指定时间安排指定任务
Timer t = new Timer();
//第一参数时安排的任务,第二个参数是执行的时间,第三个参数是过多长时间再重复执行
t.schedule(new MyTimerTask(), new Date(188, 6, 1, 14, 22, 50), 3000)

同步代码块

  1. 什么情况下需要同步
    当多线程并发,有多段代码同时执行时,我们希望某一段代码执行的过程中CPU不要切换到其他线程工作,这时就需要同步
  2. 同步代码块
    使用Synchronized关键字加上一个锁对象来定义一段代码,这就叫同步代码块。
    多个同步代码如果使用相同的锁对象,那么他们就是同步的。锁对象可以是任意的
    同步方法:使用Synchronized关键字修饰一个方法,该方法中所有的代码都是同步的
    非静态的同步方法的锁对象是this;静态的同步方法的锁对象是该类的字节码对象(.class)

线程安全
多线程并发操作同一数据时,就有可能出现线程安全问题
使用同步技术可以解决这种问题,把操作数据的代码进行同步,不要多个线程一起操作
Vector是线程安全的,ArrayList是线程不安全的
StringBuffer是线程安全的,StringBuilder是线程不安全的
Hashtable是线程安全的,HashMap是线程不安全的

死锁
多线程同步的时候,如果同步代码嵌套,使用相同锁,就有可能出现死锁

两个线程间的通信

  1. 什么时候需要线程通信
    多个线程并发进行时,在默认情况下CPU是随机切换线程的
    如果我们希望他们有规律的执行,就可以使用通信,例如每个线程执行一次打印
  2. 怎么通信
    如果希望线程等待,就调用wait()
    如果希望唤醒等待的线程,就调用notify()
    这两个方法必须在同步代码中执行,并且使用同步锁对象来调用
    3.在同步代码快中,用哪个对象锁就用哪个对象调用wait方法
    4.为什么wait和notify这些方法需要定义在Object这个类中?
    锁对象可以是任意对象,那么任意对象对应的类都是Object的子类,也就是Object是所有类的基类,所以将方法定义在Object这个类中就会让任意对象对其进行调用
    5.Sleep方法和wait方法的区别
    Sleep在同步代码块或同步函数中,不释放锁;wait在同步代码块中释放锁。
    Sleep方法必须传入参数,参数其实就是时间,时间到了,自动醒来;wait方法可以参数也可以不传,如果给wait方法传入参数,用法与sleep相似,时间到就停止等待(通常没有参数)
    互斥锁
    1. 同步****
    使用ReentrantLock类的lock()和unlock()方法进行同步
    2. 通信
    使用ReentrantLock类的newCondition()方法可以获取condition对象
    需要等待的时候使用Condition的wait()方法,唤醒的时候用signal()方法
    不同的线程使用不同的condition,这样就能区分唤醒的时候找哪个线程了
    线程的生命周期

在这里插入图片描述
二叉树的基础遍历
以根节点第几个被访问为根据

  1. 前序遍历
    先访问根节点,然后访问左子树,最后访问右子树
  2. 中序遍历
    先访问左子树,中间访问根节点,最后访问右子树
  3. 后序遍历
    先访问左子树,再访问右子树,最后访问根节点
    网络编程三要素协议
    UDP:面向无连接,数据不安全,速度快,不区分客户端与服务端
    TCP:面向连接(三次握手),数据安全,速度略低,分为客户端和服务端
    三次握手:客户端向服务端发送请求,服务端响应请求,传输数据
    TCP协议
    1 客户端
    创建Socket连接服务器端(指定ip地址,端口号)通过ip地址找对应的服务器
    调用Socket的getInputStream()和getOutputStream()方法获取和服务端相连的IO流
    输入流可以读取服务器端输出流写出的数据
    输出流可以写出数据到服务器端的输入流
    2 服务端
    创建ServerSocket(需要指定端口号)
    调用ServerSocket的accept()方法接收一个客户端请求,得到一个Socket
    调用Socket的getInputStream()和getOutputStream()方法获取和客户端相连的IO流
    输入流可以读取客户端输出流写出的数据
    输出流可以写出数据到客户端的输入流


这篇关于Java学习笔记-Java基础的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程