Java学习笔记

Java基础

1.标识符和关键词

1.1标识符

(_a1,$a, 1a(错)

1.2修饰符

1)strictfp(精确浮点类型

内部所有的float和double都是精确浮点类型

transient(不可序列化)

标识变量不可被序列化

synchronized(方法锁)

在需要同步的对象中加入此控制,synchronized可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。

volatile(强迫从共享内存中重读该成员变量的值)

volatile修饰变量。在每次被线程访问时,都强迫从共享内存中重读该成员变量的值。而且,当成员变量发生变化时,强迫线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

Java volatile关键字最全总结:原理剖析与实例讲解(简单易懂)_夏日清风-CSDN博客

Java并发编程:volatile关键字解析 - Matrix海子 - 博客园 (cnblogs.com)

https://www.cnblogs.com/dolphin0520/p/3920373.html

Native(其他语言实现方法)

native是方法修饰符。Native方法是由另外一种语言(如c/c++,FORTRAN,汇编)实现的本地方法

2.字符串处理

2.1常用类

String:少量数据

StringBuffer:线程安全

StringBuilder:线程不安全、性能好

​​​​​​​2.2StringBuffer和StringBuilder对比

​​​​​StringBuffer的方法增加了synchronized关键词修饰,线程安全。

@Override
public synchronized StringBuffer append(String str) {
    toStringCache = null;
    super.append(str);
    return this;
}

 

3. 内置包装类

3.1 内部包装类

Byte、Short、Integer、Long、Character、Float、Double、Boolean

3.2 装箱/拆箱

自动、手动

3.3 Object

clone(), finalize()……

3.4 System

out, in, err

exit()、gc()

4.数组

4.1Arrays工具类

binarySearch(先排序)

sort(倒排Collections.reverseOrder())

parallelPrefix(修改值,两参数前元素和当前元素)

修改元素值,匿名类重写方法两个参数

  1. 前一个索引处元(i=0时为1)素
  2. 当前索引元素

parallelSetAll(赋值,参数为索引号)

设置元素值,匿名重写方法一个参数

  1. 参数为索引号

parallelSort(并行排序)

4.2数组复制

int[] ints = new int[3];
int[] newInts1 = Arrays.copyOf(ints, 3);
int[] newInts2 = Arrays.copyOfRange(ints, 0, 2);

int[] newInts3 = new int[2];
System.arraycopy(ints, 0, newInts3, 0, 2);

int[] newInts4 = ints.clone();

4.3 排序

 

  1. 冒泡排序(两两连续比较,大数后移)
  2. 快速排序(每轮按照一个中间数,将数组分为两部分,再递归前后)
  3. 选择排序(每轮找到最大数,再和最后一位交换)
  4. 直接插入排序(每次把i为插入到前面合适的位置,使前面的排好序)

5. 类和对象

5.1面向对象核心特性(继承、封装、多态)

继承(单继承、多借口)

单继承避免冲突,多接口

封装(复杂性)

类的用途就是封装复杂性

多态(继承、重写、向上转型)

多态三必要条件:继承、重写、父类引用指向子类对像【向上转型】

class Animal {
    public void Eat() { System.out.println("eat food"); }
}
class Cat extends Animal { // 继承
    public void Eat() { System.out.println("eat fish"); } // 重写
}
Animal animal = new Cat(); // 向上转型
animal.Eat();
//输出  eat fish

5.2 对象创建

显示创建new、反射、clone、readObject

Java学习笔记_第1张图片

反射:className.newInstance();

clone()

java.io.ObjectlnputStream 对象的 readObject() 方法

隐式创建String、Class实例

String str = abc;

String str2 = 123” + str;

java虚拟机加载一个类时会自动创建其Class实例

 

5.3 创建步骤内存、变量默认值、初始值

分配内存

将变量初始化为默认值

给变量赋初始值

5.4.对象销毁

回收条件(引用、null)

对象引用超过其作用范围

对象被赋值null

 

 

三种状态(触及、复活)

可触及、可复活、不可触及

 

5.5.匿名对象(有堆无栈)

只在堆内存中开辟空间

没有栈内存的引用

new Person(“Li”).tell();

 

5.6.Package包

5.7.修饰符

控制:public、friendly(同包)、protected(同包、子类)、private

static:

final:类不可继承、方法不可重写、变量不可修改

6.Java继承和多态

6.1.类的封装、继承

6.2.super

this 指的是当前对象的引用,super 是当前对象的父对象的引用。

this 和 super 不能同时出现在一个构造方法里面

this( ) 和 super( ) 都指的是对象,所以,均不可以在 static 环境中使用

从本质上讲,this 是一个指向对象本身的指针, 然而 super 是一个 Java 关键字

6.3.对象类型转换

向上转型

父亲引用指向子类对象。

FatherClass fc = new SonClass();

 

 

向下转型

子类引用指向父亲对象。需要强制转换。

SonClass sc = (SonClass)fatherClass;

如果父亲对象不是子类的实现,那么这个强制转换会运行时报错。

可以加判断 instancof SonClass

 

6.4.方法重载、重写

重载:多个方法名称相同,具有不同的参数(形参列表不同),返回类型可以相同也可以不同

重写:子类覆盖父类的方法,加@Override注解

注意:

final、static方法不可以被重写;

如果不能继承一个方法,则不能重写

6.5.多态性

在父类中定义的属性和方法被子类继承之后,可以具有不同的数据类型或表现出不同的行为。

分为编译时多态和运行时多态。

3 个必要条件:继承、重写和向上转型。

向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。

6.6.instanceof 

判断一个对象是否为一个类(或接口、抽象类、父类)的实例

boolean result = obj instanceof Class

  1.  

6.7.抽象类

抽象类的定义和使用规则如下:

abstract 关键字声明。

如果一个方法被声明为抽象的,那么这个类也必须声明为抽象的。

一个抽象类中,可以有 0~n 个抽象方法,以及 0~n 个具体方法。

抽象类不能实例化,也就是不能使用 new 关键字创建对象。

抽象方法的 3 个特征

抽象方法没有方法体

抽象方法必须存在于抽象类中

子类重写父类时,必须重写父类所有的抽象方法

6.8.接口

接口声明public和private不同,public包外可用,private仅包内

方法,隐式地声明为公有的(public)和抽象的(abstract)

变量,隐式地声明位public,static,final,即常量,必须初始化

没有构造函数

6.9.Java抽象类和接口的联系和区别

6.10.内部类

外部类

编译之后有独立的.class文件,但是前面增加了外部类名称和$

外部类以外的类访问内部类

OutClass.InnerClass ic = new OutClass().new InnerClass();

 

 

静态内部类

访问控制参考静态方法

 

 

局部内部类

方法内定义的类

不能使用访问控制修饰符(public、private 和 protected)和 static 修饰符修饰

只可以访问当前方法中 final 类型的参数与变量

重名的话.this.

匿名内部类

需要在外部定义一个类、抽象类或接口;

外部类的方法内部可以new这个类(接口),并重新定义方法

可以有非静态代码块,在父类的构造函数后执行

内部类实现多重继承

抽象类Sing,方法singSong(),抽象类Dance,方法dangceDance()

类Actor extends Sing,定义匿名内部

Dangce d = new Dance(){

//重写方法danceDance()

}

调用,a.singSong(); a.d.danceDance();

effectively final

Java8开始支持的新特性;

局部内部类,或匿名内部类访问的变量必须是final,如果没有添加的话,编译器会自动将其设置为effectively final,而不需要手动修改位final,但是如果其他地方有对变量修改的话会报错

访问控制

 

7.Lambda

7.1.实现方式

定义函数式接口,@FunctionalInterface注解,只能有一个抽象方法,但可以添加默认方法和静态方法;

在使用的地方用Lambda实现接口

// 可计算接口

public interface Calculable {

    // 计算两个int数值

    int calculateInt(int a, int b);

}

Calculable cal = (int a, int b) -> {

    // 访问静态成员变量,不能访问实例成员变量

    staticValue++;

    int c = a + b + staticValue;

    // this.value;

    return c;

};

Int rst = cal(3, 5);

 

 

7.2.访问控制

Lambda 表达式只能访问局部变量而不能修改,否则会发生编译错误,但对静态变量和成员变量可读可写

 

7.3.方法引用(::)

定义方法,方法参数返回和接口方法一致

静态方法:DemoClass::add,普通方法:new DemoClass():sub

public class LambdaDemo {

// 静态方法,进行加法运算

// 参数列表要与函数式接口方法calculateInt(int a, int b)兼容

public static int add(int a, int b) {

    return a + b;

}

 

// 实例方法,进行减法运算

// 参数列表要与函数式接口方法calculateInt(int a, int b)兼容

public int sub(int a, int b) {

    return a - b;

}

}

// 打印加法计算结果,静态方法

display(LambdaDemo::add, n1, n2);

LambdaDemo d = new LambdaDemo();

// 打印减法计算结果 ,普通方法

display(d::sub, n1, n2);

 

public static void display(Calculable calc, int n1, int n2) {

    System.out.println(calc.calculateInt(n1, n2));

}

 

 

 

 

7.4.同C#Lambda对比

C#需要定义delegate

pubulic delegate int CalAdd(int a, int b);

使用的出显示声明delegate类型

CalAdd add = (int a, int b) => {return a+b};

两者的定义方式不同,C#定义delegate即可,Java没有delegate,需要定义接口并且需要@FunctionInterface注解。

8.Java异常处理

8.1.finally和return执行顺序

finally中的代码总会被执行,除非在try和catch中调用了system.exit()。

当try、catch中有return时,也会执行finally。return的时候,要注意返回值的类型,是否受到finally中代码的影响。

finally中有return时,会直接在finally中退出,导致try、catch中的return失效。

8.2.自动资源管理

Java7之前

手动在finally里释放资源,且需要再增加try catch语句

public static void main(String[] args) {

    FileInputStream fis = null;

    try {

        fis = new FileInputStream("a.txt");

    } catch (FileNotFoundException e) {

        e.printStackTrace();

    } finally {

        // 关闭磁盘文件,回收资源

        if (fis != null) {

            try {

                fis.close();

            } catch (IOException e) {

                e.printStackTrace();

            }

        }

    }

}

 

 

 

 

Java7

try (

    // 声明、初始化两个可关闭的资源

    // try语句会自动关闭这两个资源

    BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));

    PrintStream ps = new PrintStream(new FileOutputStream("a.txt"))) {

// 使用两个资源

System.out.println(br.readLine());

ps.println("C语言中文网");

}

 

 

Java9

// 有final修饰的资源

final BufferedReader br = new BufferedReader(new FileReader("AutoCloseTest.java"));

// 没有显式使用final修饰,但只要不对该变量重新赋值,该变量就是有效的

final PrintStream ps = new PrintStream(new FileOutputStream("a. txt"));

// 只要将两个资源放在try后的圆括号内即可

try (br; ps) {

    // 使用两个资源

    System.out.println(br.readLine());

    ps.println("C语言中文网");

}

    1.  

和C#对比

using (var fs = File.Open("xxxx", FileMode.Open))

{

//

}

  1.  

throws和throw:声明和抛出异常

throws声明方法可能抛出的所有异常信息,表示一种可能性,但不确定;throw则确定抛出的异常类型

方法或类处,可以通过throws声明;方法内部通过throw声明

throws由系统自动捕获异常;throw需要用户自己捕获异常,并对异常处理

子类重写父类方法,throws的异常需要是父类方法throws异常的子类或相同。

8.4.Java异常处理规则

4 个目标

成功的异常处理应该实现如下 4 个目标

使程序代码混乱最小化。

捕获并保留诊断信息。

通知合适的人员。

采用合适的方式结束异常活动。

基本准则

不要过度使用异常

不要使用过于庞大的try块

避免使用 Catch All 语句

不要忽略捕获到的异常

9.Java集合、泛型和枚举

Java集合类型分为Collection和Map,是两个根接口。

9.1.接口比较

Queue是队列的实现,Dueue在其基础上实现了双向队列;

List是个可以精准控制每个元素的插入位置;

Set不允许重复,Map存放Key-Value键值对。

9.2.实现类比较

HashSet:底层用HashMap实现,优化了查询性能,不保证顺序;

TreeSet:有序Set,内部用TreeMap实现,;

ArrayList:用数组实现,数组可变大小,可以快速随机访问元素;

核心代码:

elementData = Arrays.copyOf(elementData, newCapacity);

LinkedList:对顺序访问进行了优化,但随机访问性能较慢,一般作为Stack和Queue使用;底层使用了Node内部静态私有类,该类有next和prev字段。

HashMap:哈希算法来存取键对象;

TreeMap:可以对键对象排序,put的时候就排好序了。

9.3.List集合

ArrayList

构造方法

ArrayList():初始化容量10的空列表

ArrayList(Collection c):按照c的迭代器返回的顺序添加

增加了根据索引获取和修改元素的方法,以及根据元素获取索引的方法

ArrayList 类实现了可变数组的大小

核心代码:

elementData = Arrays.copyOf(elementData, newCapacity);

LinkedList

采用链表结构保存对象,这种结构的优点是便于向集合中插入或者删除元素

private static class Node {
    E item;
    Node next;
    Node prev;
    Node(Node prev, E element, Node next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

 

频繁向集合中插入和删除元素时,使用 LinkedList 类比 ArrayList 类效果高

随机访问元素的速度则相对较慢

只对首末元素操作便捷,可用于Stack和Queue

9.4.Set集合

HashSet

底层使用HashMap,根据Hash算法作为Key,存取和查找性能很好

添加相同的元素,后添加的会覆盖前面的,不重复

TreeSet

实现对集合进行自然排序只能对实现了 Comparable 接口的类对象进行排序

底层用TreeMap实现

9.5.Map集合

HashMap

数据存放

transient Node[] table;

Node类型定义

static class Node implements Map.Entry {
    final int hash;
    final K key;
    V value;
    Node next;

其中hash的计算方法:

static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

 

TreeMap

可以对键对象排序。

遍历

foreach

for (Map.Entry entry : users.entrySet())

迭代器

Iterator> it = users.entrySet().iterator();

keySet()和valueSet()迭代

9.6.迭代器

代码

Iterator it = objs.iterator();

while (it.hasNext()) {

String obj = (String) it.next();

}

快速失败(fail-fast)机制,是 Java Collection 集合中的一种错误检测机制。

只有通过 Iterator 的 remove() 方法删除上一次 next() 方法返回的集合元素才可以

9.7.Collections

操作 Set、List 和 Map 等集合的工具类

排序:sort()

最大、最小值:max(), min()

二分查找:binarySearch(),先排序再查找

反转顺序:reverse,reverseOrder(反转比较器)

将集合变为线程安全:synchronizedCollection,synchronizedList……

和Arrays比较,Arrays是操作数组的类

Arrays.binarySearch//二分查找

Arrays.copyOf //复制

Arrays.copyOfRange//复制部分

Arrays.sort//排序

Arrays.fill//填充

Arrays.toString//字符串返回

Arrays.hashCode//哈希值

Arrays.asList//将数组转为List

  1.  

9.8.Lambda\Predicate

forEach

objs.forEach(m-> System.out.println(m));

    1.  

removeIf

objs.removeIf(ele -> ((String) ele).length() < 12);

  1.  

9.9.Stream

Java 8 还新增了 Stream、IntStream、LongStream、DoubleStream 等流式 API

用法1

IntStream is = IntStream.builder().add(20).add(13).add(-2).add(18).build();

用法2

objs.stream().filter(ele -> ((String) ele).length() > 12).count()

中间方法

filter, mapToxxx, peek, distinct, sorted, limit

末端方法

forEach, toArray, reduce, min, max, count, findFirst, findAny, anyMatch, allMatch, noeMatch

  1.  

9.10.不可变集合

Set/List

Set.of,List.of,

Set set = Set.of("Java", "Kotlin", "Go", "Swift");

Map

Map map = Map.of("语文", 89, "数学", 82, "英语", 92);

Map map2 = Map.ofEntries(Map.entry("语文", 89), Map.entry("数学", 82), Map.entry("英语", 92));

10.Java泛型

10.1.Java是假泛型

仅是给编译器使用的,编译后会对泛型进行擦除。

证明:

先声明一个ArrayList list

然后list.Add(1)

使用反射为list添加一个字符串,可以正常添加

list.getClass().getMethod("add", Object.class).invoke(list, "asd");

并且编译后读取数据可以正确读出不报错。

10.2.对比C#

C#是真泛型,在第四步读取时会报错;

C#为每个泛型都生成了一个新的类型,为了考虑性能,CLR只会为相同的泛型组合编译一次。

11.Java枚举

自定义枚举项的值

需要声明枚举构造函数,并有int类型的参数。

每个枚举项都可以理解成是这个枚举类型,包含了其定义的属性和方法。

public enum MyEnum {
    First(100),    Second(200), Third(300);
    int state;
    MyEnum(int i) {
        state = i;
    }
    public int getState(){
        return state;
    }
}

 

自定义方法

 

 

枚举类

方法名称

描述

values()

以数组形式返回枚举类型的所有成员

valueOf()

将普通字符串转换为枚举实例

compareTo()

比较两个枚举成员在定义时的顺序

ordinal()

获取枚举成员的索引位置

 

  1.  

EnumMap与EnumSet

EnumMap 是专门为枚举类型量身定做的 Map 实现HashMap 只能接收同一枚举类型的实例作为键值

EnumSet 是枚举类型的高性能 Set 实现,它要求放入它的枚举常量必须属于同一枚举类型

12.Java反射

概念

编译期是指把源码交给编译器编译成计算机可以执行的文件的过程

运行期是把编译后的文件交给计算机执行

Java 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法

    1.  

作用

运行期判断对象的类

运行期创建对象

运行期判断类的成员变量和方法

运行期调用对象的方法

生成动态代理 Java基础之反射生成JDK动态代理 - 技术小白丁 - 博客园 (cnblogs.com)

优点

动态获取类实例,提高灵活性和扩展性;

与动态编译结合,实现无比强大的功能;

运行时装配,实现组件间解耦,更容易实现面向对象。

缺点

性能损耗

破坏封装性,导致安全问题

Class

// 1. 通过类型class静态变量
Class clz1 = String.class;
String str = "Hello";
// 2. 通过对象的getClass()方法
Class clz2 = str.getClass();

  1.  

获取类对象成员

getConstructor/getConstructors/getDeclaredConstructors

getMethod/getMethods/getDeclaredMethods

getField/getFields/getDeclaredFields

有Declare:类自身声明的构造函数、方法、成员变量,不包括父类定义

无Declare:类可以访问的public的,包括父类定义的

  1.  

setAccessible

con.setAccessible(true); // 设置允许访问 private 成员

method.setAccessible(true); // 设置为允许访问private方法

field.setAccessible(true);

  1.  

反射操作数组

获取数组元素类型

Class arrayClass = instanceArray.getClass().getComponentType();

    1.  

Array类常用API

get(Object array,int index):获取数组中指定位置的内容。

newInstance(Class componenType,int length):根据指定类型和指定长度,开辟一个新的数组

set(Object array,int index,Object value):修改数组中指定位置的内容

反射操作泛型

Java采用泛型擦除机制来引入泛型,泛型仅是给编译器Javac使用的,确报数据的安全性和免去数据类型强制转换的麻烦。但是编译一旦完成,所有和反省有关的类型全部被擦除。

为了通过反射操作泛型类型,Java引入了以下类型。他们不是Class类中的类型,但是和原始类型起名。

ParameterizedType 一种参数化类型,比如Collection< String >

GenericArrayType 一种元素类型是参数化类型或者类型变量的数组类型

TypeVariable 是各种类型变量的公共父接口

WildcardType 代表一种通配符类型表达式

13.Java输入/输出流

 

14.Java注解

基本注解

@Override:重写父类方法

@Deprecated:元素已过时,IDEA删除线标注,编译器警告

@SuppressWarnings:抑制警告

@SafeVarargs:抑制参数类型错误警告

@FunctionalInterface:为了Lambda定义的函数式接口

元注解

@Documented:注释,doc文档

@Target:作用范围

@Retention:生命周期,注解被保留的时间长短

@Inherited:继承

@Repeatable:重复

@Native

自定义注解

根据注解是否包含成员变量,可以分为如下两类

标记注解:没有定义成员变量的注解类型被称为标记注解。这种注解仅利用自身的存在与否来提供信息,如前面介绍的 @Override、@Test 等都是标记注解。

// 定义一个简单的注解类型
public @interface Test {
}

 

元数据注解:包含成员变量的注解,因为它们可以接受更多的元数据,所以也被称为元数据注解。

public @interface MyTag {
    // 定义带两个成员变量的注解
    // 注解中的成员变量以方法的形式来定义
    String name();
    int age();
}

    1.  

反射获取

getAnnotations()

你可能感兴趣的:(基础学习)