java基础

集合

集合的好处

数组

1、长度开始时必须指定,而且一旦指定,不能更改

2、保存的必须为同一类型的元素

3、使用数组进行增加元素的

Person数组扩容示意代码

Person[] pers = new Person[1];

per[0] = new Person();

重新创建数组

collection

1、可以动态保存任意多个对象,使用比较方便

2、提供了一系列方便的操作对象的方法: add,remove,set,get等

3、使用集合添加,删除新原色的示意代码- 简洁

集合框架图

1、集合主要分两种(单列集合、双列集合)

2、collection 接口有两个重要的子接口 List Set 他们的实现子类都是单列集合

3、Map 接口实现的子类 是双列集合 存放的K-V

collection接口和常用方法

public interface Collection<E> extends Iterable<E>

1、collection实现子类可以存放多个元素,每个元素可以是Object
2、有些collection的实现类,可以存放重复的元素,有些不可以
3、有些Collection的实现类,有些是有序(list) 有些不是有序(Set)
4、Collection接口没有直接的实现子类,是通过他的子接口Set和List来实现的
方法:
remove 删除指定元素
contains 查询元素是否存在
size  获取元素个数
isEmpty 判断是否为空
clear 清空
addAll 添加多个元素
containsAll 查询多个元素是否存在
removeAll 删除多个元素

collection遍历元素的方式

1、Iterator对象称为迭代器,主要用于遍历Collection集合中的元素

2、所有实现了Collection接口的集合类都有一个iterator()的方法,用于返回一个实现Iterator接口的对象,即可以返回一个迭代器

3、Iterator的结构(看一张图)

4、Iterator仅用于遍历集合,Iterator本身并不存放对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a9HSccZM-1644162092695)(D:\web\git\document\assets\image-20211228162935270.png)]

增强for循环

底层 还是迭代器

增强for 也是就简化版的迭代器

for(Object book:col){
	System.out.println()
}

List

List接口基本介绍

1、List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复

2、List集合中的每个元素都有其对应的顺序索引,即支持索引

3、List容器中的元素都对应一个整数型的序号记载骑在容器中的位置,可以根据序号存取容器中的元素

方法:
void add(int index,Object ele)  在index位置插入ele
void addAll(int index,Object eles)  在index位置插入eles的所有元素
Object get(int index) 获取指定位置的元素
int indexOf(Object obj) 返回obj在集合中首次出现的位置
int lastIndexOf(Object obj) 返回指定元素最后一次出现的位置
Object remove(int index) 移除此元素,并返回此元素
ArrayList
标记接口(注解也可以实现):空接口

RandomAccess:说明该类支持随机访问,大部分是基于数组实现
		
			遍历方式:for   迭代器

Cloneable:说明该类支持拷贝
    
    深拷贝:
    
    浅拷贝:直接使用Object中的clone方法,拷贝出来的对象不是一个独立对象
    
    传值方式:1、基本类型和String变量是值传递
       		2、引用类型是引用传递

java.io.Serializable:将对象存入网络传输、写磁盘。
    				  反序列化:从磁盘或者网络读取对象
    	serialVersionUID:类文件的指纹(签名) md5  写死就不会重新签名
    
transient Object[] elementData;  实际存储元素的地方

数组长度:长度不可变,内存是连续的,只能存储相同类型的元素

(数组中的元素占用的内存空间是相同的,对象时存的内存地址

DEFAULTCAPACITY_EMPTY_ELEMENTDATA:节省空间   说明调的是无参构造器,默认容量是10(第一次添加元素时初始化容量是10
elementData:实际存储元素的地方

calculateCapacity(elementData, minCapacity):确定需要多少容量

ArrayList 线程安全

iterator:

扩容:生成一个新数组,赋值给elementData 解决数组长度不可变的问题

cursor:游标
游标:保存了一个下标值
modCount != expectedModCount
说明list发生了变化,导致脏读  fail-fast机制


spliterator


modCount:操作数

SubList

n

Vecator

Set

HashSet

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-okXF3jTG-1644162092697)(D:\web\git\document\assets\image-20220101231920952.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AwaIfVhH-1644162092698)(D:\web\git\document\assets\image-20220101232238769.png)]

1、HashSet 实现Set类

2、HashSet实际上是HashMap

3、可以存放null值,但是只有一个null

4、HashSet不保证元素有序的,取决于hash后,再确定索引的结果

5、不能有重复元素/对象

  • 底层机制

说明:底层是hashMap,HashMap底层是(数组+链表+红黑树)

HashSet源码解读
1、执行 HashSet()

public HashSet() {
        map = new HashMap<>();
    }
    
2、执行 add()
public boolean add(E e) {
        return map.put(e, PRESENT)==null;  // PRESENT : static final Object PRESENT = new Object();
    }
    
3、执行 put() 该方法会执行hash(key) 得到key对应 的hash值 算法h = key.hashCode()) ^ (h >>> 16);
public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }

4、执行 putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; 
    	Node<K,V> p; 
    	int n, i;  // 定义了辅助变量
        if ((tab = table) == null || (n = tab.length) == 0) // table 是 HashMap的一个数组,类型是Node[] 
            n = (tab = resize()).length; // 表示如果当前table是空 或者大小=0  就第一次扩容到16个空间
        if ((p = tab[i = (n - 1) & hash]) == null) // 1、根据key 得到hash 去计算该key应该存到table表的哪个索引位置,并把这个位置的对象,赋给 p
            // 2、判断p  是否为null
            // 2.1 如果p 为空 表示还没有存放元素,就创建一个Node(key,value=PRESENT)
            // 2.2 就放到该位置 table[i] = new Node(hash, key, value, null);
            tab[i] = newNode(hash, key, value, null);
        else {
            // 一个开发技巧提示 :  在需要局部变量(辅助变量)时候  在创建
            Node<K,V> e; 
            K k;// 辅助变量
            // 如果当前索引位置对应的链表第一个元素和准备添加的key的hash值一样、
            // 并且满足以下两个条件
            // (1) 并且满足 准备加入的key 和 p 指向的Node 结点的key 是同一个对象
            // (2) p 指向的Node 结点的key 的equals() 和准备加入的key 比较后相同
            if (p.hash == hash && 
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            // 再判断p 是不是一颗红黑树
            // 如果是一颗红黑树,在调用 putTreeVal ,来添加
            else if (p instanceof TreeNode)
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else { //如果table对应索引位置,已经是一个链表,就使用for循环比较
                   // (1)依次和该链表的每个元素比较后,都不相同,则加入该链表最后
                   // 	  注意在把元素添加到链表后,立即判断,该链表是否已经达到8个结点
                   // 	  就调用 treeifyBin() 对当前这个链表进行树化(转成红黑树)
                   //     注意,在转成红黑树时,要进行判断,判断条件如下 (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)   resize();
                   // 	  如果上面条件成立,先table扩容
                   //     只有上面条件不成立,才进行转成红黑树                          
                   // (2)依次和该链表的每个元素的比较过程中,如果有相同的情况,就直接break
                   
                for (int binCount = 0; ; ++binCount) {
                    if ((e = p.next) == null) {
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                            treeifyBin(tab, hash);
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;
        if (++size > threshold)
            resize();
        afterNodeInsertion(evict);
        return null;
    }
LinkedHashSet

1、LinkedHashSet是HashSet的子类

2、LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表

3、LinkedHashSet根据元素的HashCode值决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的

4、LinkedHashSet不允许添重复元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TSAw0JWY-1644162092700)(D:\web\git\document\assets\image-20220102110811939.png)]

Map

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KENl181n-1644162092702)(D:\web\git\document\assets\image-20220102121404974.png)]

1、双列元素(K-V)

2、

注解和反射

注解可以被其他程序读取

常用的注解

@Override 重写超类中的另一个方法声明

@Deprecated 不鼓励使用

@SuppressWarnings 抑制编译时的警告信息 参数(“all”,“unchecked”,"")

元注解

元注解的作用就是负责注解其他注解,Java定义了4个标准的meta-annotation类型,他们被用来提供对其他annotation类型作说明

@Target 用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
@Retention 表示需要在什么级别保存改注释信息,用于描述注解的生命周期(source<class<runtime)
@Document 说明改注解将被包含在javadoc中
@Inherited 说明子类可以继承父类中的该注解

自定义注解

使用@Interface自定义注解时,自动继承了java.lang.annotation.Annotation接口

1、@Interface用来声明一个注解,格式:pubic @Interface 注解名(定义内容)

2、其中的每个方法实际上是声明了一个配置参数

3、方法的名称就是参数的名称

4、返回值类型就是参数的类型(返回值只能是基本类型:class,String,enum)

5、可以通过default来声明参数的默认值

6、如果只有一个参数成员,一般参数名为value

7、注解元素必须要写值,我们定义注解元素是,经常使用空字符串,0作为默认值

public class annocation {

    @SecAnnotation("默认")
    @MyAnnotation(age = 12)
    public void test(){

    }
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
@interface MyAnnotation{
    // 注解的参数
    String name() default "小米";
    int age();

    String[] schools() default {"第一","第二"};
}

@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
@interface SecAnnotation{
    String value();
}

反射机制

动态语言

javaScript

静态语言

Java不是动态语言,但可以称之为"准动态语言"

Java Reflection

Reflection(反射)是Java被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

Class c = class.forName("java.lang.String")

加载完类之后,在堆内存的方法中就产生了一个Class类型的对象(一个类只要有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们称之为:反射

反射方式:
实例化对象————》getClass()方法——————》得到完整的“包类”名称

Java反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

优缺点

  • 可以实现动态创建对象和编译,体现出很大的灵活性

缺点:

  • 对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于 直接执行相同的操作。

主要API

  • java.lang.Class 代表一个类
  • java.lang.reflect.Method 代表类的方法
  • java.lang.reflect.Field 代表类的成员变量
  • java.lang.reflect.Constructor 代表类的构造器

Class类

在Object类中定义了一下的方法,此方法将被所有子类继承

public final Class getClass()

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现类哪些接口。对于每个类而言,JRE都为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个结构

  • Class本身也是一个类
  • Class对象只能由系统建立对象
  • 一个加载的类在JVM中只会有一个Class实例
  • 一个Class对象对应的是一个加载到JVM中的一个class文件
  • 每个类的实例都会记得自己是由哪个Class实例所生成
  • 通过Class可以完整地得到一个类中的所有被加载的结构
  • class类是Reflection的根源,针对任何你想动态加载、运行的类,唯有先获取相应的Class对象

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yxIG0tNQ-1644162092705)(D:\web\git\document\assets\image-20220120162801518.png)]

获取Class类的实例

  1. 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
Class clazz = Person.class
  1. 已知某个类的实例,调用该实例的getClass()方法获取Class对象
Class clazz = person.getClass();
  1. 已知一个类的全类目,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
Class clazz = Class.forName("demo1.student")
  1. 内置基本数据类型可以直接用类名.Type
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        // 通过反射获取类的Class对象
        Class c1 = Class.forName("com.test.study.reflect.User");

        System.out.println(c1);

        Class c2= Class.forName("com.test.study.reflect.User");
        Class c3 = Class.forName("com.test.study.reflect.User");
        Class c4 = Class.forName("com.test.study.reflect.User");

        // 一个类在内存中只有一个Class对象
        // 一个类被加载后,类的整个结构都会被封装在Class对象中
        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());


        User user = new User();
        // 方法一 :通过对象获得
        Class d1 = user.getClass();
        System.out.println(d1.hashCode());
        // 方法二:通过forname获得
        Class d2 = Class.forName("com.test.study.reflect.User");
        System.out.println(d2.hashCode());
        // 方法三:通过类名.class
        Class userClass = User.class;
        System.out.println(userClass.hashCode());
        // 方式四:基本内置属性的包装类都一个Type属性
        Class<Integer> type = Integer.TYPE;// int
        System.out.println(type);

        // 获取父类属性
        Class d5 = d1.getSuperclass(); // class java.lang.Object
        System.out.println(d5);
    }


}


class User extends Object{}

哪些类型可以有Class对象?

  • Class:外部类,成员(成员内部类、静态内部类),局部内部类,匿名内部类
  • interface:接口
  • [] 数组
  • enum : 枚举
  • annotation: 注解@interface
  • primitive type: 基本数据类型
  • void
Class c1 = Object.class; // 类
Class c2 = Comparable.class; // 接口
Class c3 = String[].class; // 一维数组
Class c4 = int[][].class; // 二维数据
Class c5 = Override.class; // 注解
Class c6 = ElementType.class; // 枚举
Class c7 = Integer.class; // 基本数据类型
Class c8 = void.class; // void
Class c9 = Class.class; // Class
        
========================
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
interface java.lang.Override
class java.lang.annotation.ElementType
class java.lang.Integer
void
class java.lang.Class

Java内存

  • 存放new的对象和数组
  • 可以被所有的线程共享,不会存放别的对象引用
  • 存放基本变量类型(会包含这个基本类型的具体数值)
  • 引用对象的变量(会存放这个引用在堆里面的具体地址)
方法区
  • 可以被所有的线程共享
  • 包含了所有的class和static变量

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xeC04CDb-1644162092706)(D:\web\git\document\assets\image-20220120192018210.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N6ZAzvad-1644162092706)(D:\web\git\document\assets\image-20220120233339652.png)]

public class Test05 {
    public static void main(String[] args) {
        A a = new A();
        System.out.println(a);
        /*
        1、加载到内存,会产生一个类对应的class对象
        2、链接,链接结束后 m = 0
        3、初始化
        	<clinit>(){
        			System.out.println("A类静态代码块");
        			m = 300;
        			m = 100;
        	}
        m = 100
        */
    }
}

class A{
    static {
        System.out.println("A类静态代码块");
        m = 300;
    }

    static int m = 100;
    public A(){
        System.out.println("A类的无参构造初始化");
    }
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pBqBJGOV-1644162092707)(D:\web\git\document\assets\image-20220121001355404.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yWjiYGDk-1644162092708)(D:\web\git\document\assets\image-20220121001421379.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zVX6iPSB-1644162092710)(D:\web\git\document\assets\image-20220121001804204.png)]

// 通过反射获取类的Class对象
        Class c1 = Class.forName("com.test.study.reflect.User");

        // 获得类的名字
        System.out.println(c1.getName()); // 获得包名 + 类名
        System.out.println(c1.getSimpleName()); // 获得类名

        // 获得类的属性
        Field[] fields = c1.getFields(); // 只能找到public属性
        fields = c1.getDeclaredFields(); // 找全部的属性
        for(Field field:fields){
            System.out.println(field);
        }

        // 获得指定属性的值
        Field name = c1.getDeclaredField("name");
        System.out.println(name);

        // 获得类的方法
        Method[] methods = c1.getMethods(); // 获得本类及其父类的全部public方法
        for (Method method: methods) {
            System.out.println("正常的"+method);
        }
        methods = c1.getDeclaredMethods(); // 获得本类的所有方法
        for (Method method: methods) {
            System.out.println("getDeclaredMethods"+method);
        }

        // 获得指定方法
        Method getName = c1.getMethod("getName", null);
        Method setName = c1.getMethod("setName", String.class);
        System.out.println(getName);
        System.out.println(setName);

        // 获得指定的构造器
        System.out.println("======================");
        Constructor[] constructor = c1.getConstructors();
        for (Constructor constructor1 : constructor) {
            System.out.println(constructor);
        }
        Constructor[] declaredConstructors = c1.getDeclaredConstructors();
        for (Constructor declaredConstructor : declaredConstructors) {
            System.out.println("###"+declaredConstructor);
        }

        // 获得指定构造器
        c1.getDeclaredConstructor(String.class,int.class);
        System.out.println("指定构造器");
  

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FCugOu7q-1644162092711)(D:\web\git\document\assets\image-20220121011213703.png)]

// 获得Class对象
        Class c1 = Class.forName("com.test.study.reflect.User");
        // 构造一个对象
        User user = (User) c1.newInstance();
        System.out.println(user);

        // 通过构造器创建对象
        Constructor declaredConstructor = c1.getDeclaredConstructor(Integer.class,String.class);
        User user2 = (User)declaredConstructor.newInstance(11,"清");
        System.out.println(user2);

        // 通过反射调用普通方法
        User user3 = (User) c1.newInstance();
        // 通过反射获取一个方法
        Method setName = c1.getDeclaredMethod("setName", String.class);
        // invoke 激活的意思
        // (对象,“方法的值”)
        setName.invoke(user3,"小绵羊");
        System.out.println(user3.getName());

        // 通过反射操作属性
        User user4 = (User)c1.newInstance();
        Field name = c1.getDeclaredField("name");

        // 不能直接操作私有属性,我们需要关闭程序的安全检测,属性或者方法的setAccessible(true)
        name.setAccessible(true);
        name.set(user4,"操作属性");
        System.out.println(user4.getName());        

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-m06sAYih-1644162092712)(D:\web\git\document\assets\image-20220121164439896.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-y3xNu9Be-1644162092712)(D:\web\git\document\assets\image-20220121164510369.png)]

反射操作泛型

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jqG7Krlg-1644162092713)(D:\web\git\document\assets\image-20220121171603711.png)]

public void test01(Map<String,User> map, List<User> list){
        System.out.println("test01");
    }
    public Map<String,User> test02(){
        System.out.println("test02");
        return null;
    }
    public static void main(String[] args) throws NoSuchMethodException {
        Method method = Test09.class.getMethod("test01", Map.class, List.class);
        Type[] genericParameterTypes = method.getGenericParameterTypes();
        for (Type genericParameterType : genericParameterTypes) {
            System.out.println("#" + genericParameterType);
            if (genericParameterType instanceof ParameterizedType) {
                Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
                for (Type actualTypeArgument : actualTypeArguments) {
                    System.out.println(actualTypeArgument);
                }
            }

        }
        Method method1 = Test09.class.getMethod("test02", null);
        Type genericReturnType = method1.getGenericReturnType();
        if (genericReturnType instanceof ParameterizedType) {
            Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
            for (Type actualTypeArgument : actualTypeArguments) {
                System.out.println(actualTypeArgument);
            }

        }
    }

······
Type[] actualTypeArguments = ((ParameterizedType) genericParameterType).getActualTypeArguments();
for (Type actualTypeArgument : actualTypeArguments) {
System.out.println(actualTypeArgument);
}
}

    }
    Method method1 = Test09.class.getMethod("test02", null);
    Type genericReturnType = method1.getGenericReturnType();
    if (genericReturnType instanceof ParameterizedType) {
        Type[] actualTypeArguments = ((ParameterizedType) genericReturnType).getActualTypeArguments();
        for (Type actualTypeArgument : actualTypeArguments) {
            System.out.println(actualTypeArgument);
        }

    }
}

······
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值