目录
目录
2021-12-18更
一、基础
1、命名规范
包名 | 全部小写 | xxxyyyzzz |
类,接口名 | 大驼峰 | XxxYyyZzz |
变量方法名 | 小驼峰 | xxxYyyZzz |
常量名 | 全部大写 | XXX_YYY_ZZZ |
2、基本数据类型的长度
byte | 1字节 | float | 4字节 |
short | 2字节 | double | 8字节 |
int | 4字节 | char | 2字节 |
long | 8字节 | boolean | 1字节 |
3、逻辑运算符注意事项
4、三元运算符
(我爱你)?娶你:分手;
####如果我真的爱你,那么我就娶你,如果是假的就分手把!
5、循环之switch //case必须是常量
二、数组
1、foreach循环遍历数组
public static void main(String[] args) {
double[] arr01 = {1.9, 2.9, 3.4, 3.5};
// 打印所有数组元素
for (double element: arr01) {
System.out.println(element);
}
}
//直接打印的方法
System.out.println(Arrays.toString(arr01));
2.暂时还没有想到。。。。。。
三、面向对象
1、杂项
1、匿名对象
直接new Object().方法,就是不起名字,直接调用。用于一次性使用或者作为参数。
2、成员变量也就是属性,存在于堆空间,有默认值。
局部变量存在于栈空间,没有默认值。
3、方法的重载
在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数
类型不同即可。
4、可变形参
public class test3 {
public static void main(String[] args) {
test("a","b","c");
}
public static void test(String...str){
System.out.println(str[1]); //b
System.out.println(str.length); //3
}
}
5、方法的值传递机制
对于基本数据类型,传入的是实际的数值
对于引用数据类型,传入的是地址值
下面是经典的题,可以试试。
public class test3 {
public static void main(String[] args) {
int a = 10;
int b = 20;
method(a,b); //编写方法使得调换a和b的数值。
}
}
6、将对象作为参数传递给方法,一个比较神奇的设定,你可以把一个🐖的实例塞进去。
7、递归,主要就是递归公式和结束条件两方面。下面写一下n的阶乘~
public class test4 {
public static void main(String[] args) {
System.out.println(jiechen(6));
}
public static int jiechen(int n) {
int flag = 0;
if (n == 1) {
return 1;
} else {
return n * jiechen(n - 1);
}
}
}
8、属性的赋值顺序
①默认初始化 ②显式初始化 ③构造器赋值 ④通过方法调用赋值
9、JavaBean
符合①类是公共的②有一个无参的公共构造器③提供get和set方法
10、面试题:==和equals的爱恨情仇
- == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型
就是比较内存地址 - equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也
是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中
用的比较多,久而久之,形成了equals是比较值的错误观点。 - 具体要看自定义类里有没有重写Object的equals方法来判断。
11、static关键字
用来修饰属性、方法、代码块、内部类,被static修饰后,随着类的加载而加载,被所有对象共享
2、封装
下面才是真正的走进java面向对象的大门----封装
封装顾名思义就是把一个东西封存起来,至于是哪些东西呢,肯定是见不得人的东西,把一些复杂的结构封装起来,只对外暴露简单的接口,提高了系统的可扩展性和可维护性。
下面的表懒得手打,就直接拉过来了😀
2021-12-18AM更
3、构造器(构造方法)
1、构造器就是用来new对象的,并且可以给对象初始化(比如让她天生丽质🤭),每个类都会提供一个空参构造器,当然你如果不满意可以重载若干个构造器,当你重载后,默认提供的就会偷偷的跑掉。根据习惯,重载时再补上一个空参构造器。需要注意的是,继承时构造器不会被子类继承。
2、如果一个类中声明了n个构造器,则最多有n - 1个构造器中使用了"this(形参列表)"
在类的一个构造器中,最多只能声明一个"this(形参列表)"
4、继承
子承父业,发扬光大,说的就是继承后,子类比父类的功能更加强大丰富,减少了代码的冗余,毕竟爸爸打下的天下,我为何还要自己打一遍,那不是造反呢。继承的出现为后面的多态埋下了伏笔。当然需要注意的是,不要为了实现父类一点点的功能而去继承,不值得。
1、继承后获得了父类的属性方法,当然不包括private的属性方法
2、使用extends关键字,不能多继承。
3、方法的重写(与上面的方法重载放一起是面试重点)
- 方法名与参数列表保持一致
- 返回值类型不能大于父类
- 权限修饰符不能小于父类
- 抛出的异常不能大于父类
- 用时声明为为static的
4、关于继承后构造器的问题
- 子类中所有的构造器默认都会访问父类中空参构造器
- 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行
- 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错
5、多态
1、定义:父类的引用指向子类的对象
Person person = new Son();
2、前提条件:①需要存在继承或者实现关系 ②有方法的重写
3、成员变量不具备多态。
4、instanceof方法,判断前者是否是后者的实例或者子类的实例
jiayiing instanceof Person //true
5、向上转型,向下转型。
6、包装类
1、java设计之初就是一个面向对象的编程语言,然而基本数据类型的出现,就让它变得不那么面向对象,包装类的出现就是为了解决这个问题。
2、接下来就是涉及到基本数据类型,包装类以及String之间相互的转换
①基本数据类型<===>包装类
这里有自动装箱与自动拆箱
②基本数据类型<===>String
public static void main(String[] args) {
int a = 5;
String str01 = 5+"";
String str02 = "6";
int i = parseInt(str02);
}
7、设计模式
1、单例设计模式
单例设计模式就是只会产生一个对象实例,根据生成的时间又分为饿汉式和懒汉式
8、代码块
9、抽象方法与抽象类
1、含有抽象方法的类一定是抽象类,用abstract修饰。抽象类是被用来继承,抽象类不能被实例化,继承后需要重写抽象方法。
10、接口
1、接口(interface)是抽象方法和常量值定义的集合。
2、 接口中的所有成员变量都默认是由public static final修饰的。
接口中的所有抽象方法都默认是由public abstract修饰的。
11、内部类
目前几乎用不到,对于我来说,顾不进行介绍
四、异常类
1、常见的异常类型
- 角标越界
- 空指针
- 类型转换异常
2、异常的处理方式一
try{
//有可能出错的代码段
}catch(错误类型 变量){
处理的代码段}finally{
}
3、异常的处理方式二
throws Exception //直接扔出去
4、手动抛出异常 throw
5、自定义异常类
五、多线程
1、多线程的创建
方式一:继承Thread类
public class ThreadTest extends Thread {
/*
1) 定义子类继承Thread类。
2) 子类中重写Thread类中的run方法。
3) 创建Thread子类对象,即创建了线程对象。
4) 调用线程对象start方法:启动线程,调用run方法。
*/
@Override
public void run() {
for(int i=0;i<50;i++){
System.out.println(Thread.currentThread().getName()+" "+i);
}
}
}
class test_thread{
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
ThreadTest threadTest2 = new ThreadTest();
ThreadTest threadTest3 = new ThreadTest();
threadTest.start();
threadTest2.start();
threadTest3.start();
}
}
方式二:实现runnable接口
//①实现Runnable接口
class number2 implements Runnable {
//②实现run()方法
@Override
public void run() {
for (int i = 0; i < 100; i++) {
if (i % 2 == 0) {
System.out.println(Thread.currentThread().getName() + i);
}
}
}
}
public class Runnable_Test {
public static void main(String[] args) {
//③实例化number2的对象
number2 num = new number2();
//④把对象作为参数传递给Thread的构造器
Thread b1 = new Thread(num);
Thread b2 = new Thread(num);
Thread b3 = new Thread(num);
b1.setName("线程一:");
b2.setName("线程二:");
b3.setName("线程三:");
//⑤调用start方法
b1.start();
b2.start();
b3.start();
}
}
方式三和四目前不研究,对于我来说入门即可,后续如果用再做补充
通过实现Callable接口和线程池
2、线程的生命周期
1、线程的状态
新建=》就绪=》运行=》阻塞=》死亡
3、线程的同步
1、多线程会出现安全问题,因为多个线程同时处理一个数据时,当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。,最经典的就是银行存取钱的问题。
2、解决办法
4、线程的通信问题
这个东东可以让两个线程交替打印消息
六、常用类
1、String
public class StringTest {
public static void main(String[] args) {
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
String s4 = "b";
String s5 = "ab";
System.out.println(s1==s2);
System.out.println(s1==s3);
System.out.println(s1+s4==s5);
System.out.println(s1+"b"==s5);
}
}
String的具体方法,点击链接
2、StringBuilder和StringBuffer
StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全
3、时间api
此方面涉及的比较多,而且一般我用的比较少,后续可能会补上
public class DateTest {
public static void main(String[] args) {
Date date = new Date();
//获取当前时间的时间戳 13位的毫秒数
System.out.println(date.getTime());
//获取当前时间的时间戳13位的毫秒数
System.out.println(System.currentTimeMillis());
//Thu Dec 30 14:24:44 CST 2021
System.out.println(date.toString());
}
}
时间戳转为标准时间
public static String stampToDate(long s){
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = new Date(s);
return simpleDateFormat.format(date);
}
4、java比较器
java比较器是用来比较两个对象的。比如比一下身高体重啥的啦!😎
- 自然排序:java.lang.Comparable
- 定制排序:java.util.Comparator
1、首先将自然排序,要实现Comparable 的类并且实现compareTo(Object obj) 方法,两个对象即
通过compareTo(Object obj) 方法的返回值来比较大小。如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零。
public class PersonSort {
public static void main(String[] args) {
Person [] list1 = new Person[4];
Person p1 = new Person("gaoruixia", 38);
Person p2 = new Person("jiayixing", 18);
Person p3 = new Person("gaogao", 8);
Person p4 = new Person("jiajia", 48);
list1[0] = p1;
list1[1] = p2;
list1[2] = p3;
list1[3] = p4;
Arrays.sort(list1);
System.out.println(Arrays.toString(list1));
}
}
class Person implements Comparable<Person>{
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public int compareTo(Person o) {
if(this.age>o.age){
return 1;
}else if(this.age<o.age){
return -1;
}
return 0;
}
}
2、当第一种方法不方便实现Comparable方法时,采用第二种,Comparator()
Goods[] all = new Goods[4];
all[0] = new Goods("War and Peace", 100);
all[1] = new Goods("Childhood", 80);
all[2] = new Goods("Scarlet and Black", 140);
all[3] = new Goods("Notre Dame de Paris", 120);
Arrays.sort(all, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Goods g1 = (Goods) o1;
Goods g2 = (Goods) o2;
return g1.getName().compareTo(g2.getName());
}
});
System.out.println(Arrays.toString(all));
5、Math类
七、枚举类
1、枚举类的对象个数是确定的,如星期,季节等,目前用的少,后续研究
public enum SeasonEnum {
SPRING("春天","春风又绿江南岸"),
SUMMER("夏天","映日荷花别样红"),
AUTUMN("秋天","秋水共长天一色"),
WINTER("冬天","窗含西岭千秋雪");
private final String seasonName;
private final String seasonDesc;
private SeasonEnum(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
}
八、注解
1、注解(Annotation)不是注释,用@使用
注解一般在框架中大量使用,配合反射,后边用到进行补充。。。。。。。。
九、集合
这是面试的重中之重重重重。。。。。。。
首先介绍一下集合家族成员
如果你看过源码就会发现Collection实现了Iterable<E>,然后就会获得iterator() 方法,这就是迭代器,迭代器也是一种设计模式,用来遍历集合
public class Itraeasd {
public static void main(String[] args) {
ArrayList<Integer> l = new ArrayList<Integer>();
l.add(5);
l.add(53);
l.add(55);
l.add(52);
l.add(56);
Iterator<Integer> iterator = l.iterator();
while (iterator.hasNext()){ //判断是否存在下一个数据
Integer next = iterator.next(); //返回并指针下移
if(next.equals(5)){
iterator.remove(); //删除元素
}
}
System.out.println(l);
}
}
这里还要提到之前的foreach,不仅可以用来遍历数组,对于集合同样也是适用的,他的底层也是使用迭代器
1、List家族
List主要有三个成员,他们是Arraylist,Linklist,Vector
List里面的数据是有序且可重复的
Arraylist
arraylist底层是一个“变长”的数组,初始长度不指定的话默认是10,在jdk8.0以前,采用的饿汉式创建,在之后采用的是懒汉式。
这里提到一个方法
Arrays.asList() 这里的返回值是一个长度不可变的List
LinkList
linklist底层采用双向链表实现的,定义了一个头部一个尾部,用来记录前后的地址值,好处就是便于频繁的插入或者删除
Vector
这是一个古老的集合,线程安全,但是代价就是慢慢慢慢慢的,不介意使用
2、Set
Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。Set 判断两个对象是否相同不是使用== 运算符,而是根据equals() 方法。
HashSet
1、特点:不能保证排列顺序 线程不安全 可以是null
2、如何判断两个元素是否相等,首先判断hashcode(),然后判断equals(),都相等才是相等
3、对于放在set数组中的对象,一定要重写这两个方法,以实现对象相等原则,即相等的对象必须有相等的散列码。
如果不知道hash算法,理解起来有一丢丢困难,这里推荐一本不错的书
https://item.jd.com/13293434.htmlhttps://item.jd.com/13293434.html4、hashset的底层是数组,初始容量是16,当使用频率超过0.75,自动扩容两倍。
LinkHashSet
这是在HashSet的基础上增加了双向列表,可以在存入数据的时候,看似有序,插入性能略低于HashSet,但是在迭代时访问有很好的性能。
TreeSet
底层采用了红黑树,保证了集合元素始终处于排序状态。红黑树在后面的HashMap会再次和大家相遇。
3、Map
下面来到了大名鼎鼎的map家族,他的存储方式很特别,使用的是键值对,键的底层存储使用的是set集合来保证唯一性,这就类似于函数,一个键能找到唯一一个与之对应的值。再来回顾一下继承结构,使用最最最最频繁的就是HashMap
HashMap
1、允许键和值使用NULL值,不保证映射顺序,所有的Key都是使用Set集合来存放,所在类要重写equals()方法和hashCode()方法;所有的Value都是Collection,所在类要重写equals()方法。
2、一个Key-Value构成一个entry,所有的entry构成的集合是Set无序的,不可重复的。
3、JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)
JDK 8版本发布以后:HashMap是数组+链表+红黑树实现,当链表长度大于8时,会自动转换为红黑树,因为红黑树的效率比较高。
4、hashmap添加元素的过程,看起来比较繁琐,打个比喻就是根据你的hash值去寻找你的坑位,如果坑位没有人,那就把你放进去,如果有,这个时候就得调用equals方法来判断是否相同,如果不同,通过链表把你放进去,如果相同,用你的value去替换他的value。
5、hashmap扩容,当存入的数据越来越多,哈希碰撞的几率就会越来越大,效率就会下降,所以需要进行扩容,扩大为原来的一倍空间, 当数据达到容量的0.75时进行扩容,扩容之后,所有数据的hash值都要重新计算,放入新的位置,这是一个很浪费资源的过程,所以我们如果提前预知要放入数据的多少,提前选择创建的大小,尽可能的避免扩容。
6、当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。
LinkedHashMap
- LinkedHashMap 是HashMap 的子类
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
- 与LinkedHashSet类似,LinkedHashMap 可以维护Map 的迭代顺序:迭代顺序与Key-Value 对的插入顺序一致
TreeMap
Hashtable
一个古老的键值对集合,线程安全,不能存放NULL。
学了这么多先来一个小结
ArrayList | LinkList | Vector |
HashSet | LinkHashSet | Treeset |
HashMap | LinkedHashMap | TreeMap |
首先,在2020-01-01恭喜大家元旦快乐
十、泛型
在以前,一个List的集合,里面可以放各种各样的数据类型,这样不便于管理,于是给List贴上一个标签,规定了里面可以放些什么东西。<泛型类型>
1、在集合中使用泛型
ArrayList<Integer> list = new ArrayList<>();//类型推断
list.add(78);
list.add(88);
list.add(77);
list.add(66);
for(Integer i : list){
不需要强转
System.out.println(i);
}
2、自定义泛型结构
泛型类
public class Testt9<E> {
public E ttt(E aa){
System.out.println(aa);
return aa;
}
}
class Test77{
public static void main(String[] args) {
Testt9<String> stringTestt9 = new Testt9<String>();
stringTestt9.ttt("dddd");
}
}
泛型方法
public class Test5 {
public static void main(String[] args) {
tt(43);
}
public static <E> E tt(E a){
System.out.println(a);
return a;
}
}
十一、IO流
1、File类的使用
1、先来认识一下file类的构造器,第一个是最常用的。
常用方法一大堆,粘贴过来的,想看就看看
File类的获取功能 public String getAbsolutePath():获取绝对路径
public String getPath() :获取路径
public String getName() :获取名称
public String getParent():获取上层文件目录路径。若无,返回null
public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
public long lastModified() :获取最后一次的修改时间,毫秒值
public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
File类的重命名功能 public boolean renameTo(File dest):把文件重命名为指定的文件路径
public boolean isDirectory():判断是否是文件目录
public boolean isFile() :判断是否是文件
public boolean exists() :判断是否存在
public boolean canRead() :判断是否可读
public boolean canWrite() :判断是否可写
public boolean isHidden() :判断是否隐藏
File类的创建功能 public boolean createNewFile() :创建文件。若存在,则不创建,返回false
public boolean mkdir() :创建文件目录。如果存在,就不创建。如果此文件目录的上层目录不存在,也不创建。
public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目
路径下。
File类的删除功能 public boolean delete():删除文件或者文件夹
删除注意事项:
Java中的删除不走回收站。要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录
2、IO流原理及流的分类
前面引入File,现在正式的进入了IO流,I:input,O:output,流:Stream
3、节点流
还有fileinputstream和fileoutputstream,使用这个可以给图片加密
public class FIPSt {
public static void main(String[] args) throws IOException {
File file = new File("E:\\pic.jpg");
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(new File("E:\\picss.jpg"));
byte[] bytes = new byte[102400];
fis.read(bytes);
System.out.println(bytes[0]);
bytes[0]=4;
fos.write(bytes);
fis.close();
fos.close();
}
}
4、缓冲流
为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。
使用缓冲流是要在节点流上套壳
flush()可以强制将缓冲区的内容全部写入输出流
下面的代码自行体会
BufferedReader br = null;
BufferedWriter bw = null;
try {
// 创建缓冲流对象:它是处理流,是对节点流的包装
br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
String str;
while ((str = br.readLine()) != null) { // 一次读取字符文本文件的一行字符
bw.write(str); // 一次写入一行字符串
bw.newLine(); // 写入行分隔符
}
bw.flush(); // 刷新缓冲区
} catch (IOException e) {
e.printStackTrace();
} finally {
// 关闭IO流对象
try {
if (bw != null) {
bw.close(); // 关闭过滤流时,会自动关闭它所包装的底层节点流
}
} catch (IOException e) {
e.printStackTrace();
}
try {
if (br != null) {
br.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
5、转换流
当字节流转为字符流时,就得考虑编码方式
6、标准输入输出流,打印流、数据流
略
7、对象流
ObjectInputStream和OjbectOutputSteam
对应的就是反序列化和序列化,序列化是☞把一个对象实例转化为字节流进行网络传输。
对象所在类要实现Serializable接口才可以进行序列化。
序列化
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韩梅梅", 18, "中华大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();
反序列化
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();
8、随机存储文件流
9、Java NIO
到此IO告一段落了。
十二、网络编程
1、回顾计算机网络
1、这张图可以说是计算机网络祖师爷级别的存在
2、Socket套接字
网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。
2、TCP网络编程
客户端
服务端
tcp的先到这里告一段落
3、UDP编程
十三、反射,java8、9、10、11新特性
暂时不更,几乎用不到
完结于2022-01-01 21:22:00
全文共计15550