javaSE基础

1.java语言:
    静态强类型语言
        静态类型   |    动态类型
           -------  -------
        强类型     |    弱类型

        动态语言和静态语言:
            python -    动态类型
            c c++ java -    静态类型

            动态语言定义变量的时候不需要定义变量的数据类型 真正的数据类型在运行阶段赋值的时候才会确定
            静态语言定义变量的时候需要定义变量的数据类型 

        强类型语言和弱类型语言:
            强类型:定义一个变量的时候就已经确定了变量所在空间的数据类型,不能保存其他类型的数据
            弱类型:变量的内存空间任何数据类型都能存放

2.java程序的执行过程:
    .java -> javac.exe -> .class -> jvm 运行
             编译

    编写-> 编译 -> 运行

    除了java 和 javac以外 你还接触过哪些工具?
        1.jar.exe -> 把javase项目打包成jar包  web项目打包成war包

            部署一个web项目,直接把war包放在tomcat的webapps这个文件下下面

        2.javadoc.exe -> 如果我的项目按照javadoc的标准来编写注释的话,javadoc就会自动帮你生成api文档

            api文档很重要!  后端提供数据 前端调用后端接口来访问数据 中间通过json进行数据交换

        3.javap.exe ->  .class文件反编译 

            .class文件交给jvm运行的时候,会变成一条条的指令进行执行 

            编译时的特性:
                1.常量优化机制 : 如果参与运算的两个数值都是字面值常量的话 ,就会在编译阶段运行完毕
                2.泛型 
                3.foreach循环 ; for(User user : List<User>){

                                }
                                -> 
                                while(List<User>.hasNext()){
                                    List<User>.next()
                                }

            反射:
                反射最大的意义,是在程序运行的时候,获取类的信息(类名,类的修饰符,成员变量,成员变量的修饰符,访问控制权限,方法名,参数列表,返回值)
                User user = new User();
                1.把.class文件 ClassLoader(类加载器) 加载进方法区
                    怎么进行加载的?
                    .class文件 包含了这个类的所有信息 
                    根据这些信息 实例化一个 Class类的一个对象
                        获得Class类的对象方法:
                            1.类名.class
                            2.Class.forname(类名)
                                1.Fields[] -> 成员变量 每一个成员变量 都是 一个 Field 类的实例
                    class --- 
                                2.Methods[] -> 成员方法 每一个成员方法 都是一个 Method 类的实例

                    举例:
                        class Student{
                            private int age = 10;
                            public String name = "张三";

                            public void read(){

                            } 
                        }

                        1. Class student = Student.class
                        2. student.getFields() -> Field[] 里面的每一个Field对象都是一个属性 
                            student.getMethods() -> Method[] 里面的每一个Method都是一个方法
                2.在栈内存里面开辟一个空间存放变量user 这块空间的数据类型是User

                    栈:方法栈
                        方法栈里面保存的是每一个被调用方法的栈帧,每一个方法调用的时候就会把这个方法的栈帧给压栈,方法执行完毕以后,就会出栈
                        (栈顶方法永远是正在运行的方法)

                3.在堆内存里面 new一个user对象出来,然后将变量user指向这个对象 

                    如果这个方法执行完毕了,user变量没有了,因为栈帧已经出栈了,new User()还在

                    java的gc机制:
                        1.垃圾的意义:没有引用指向的对象
                        2.什么时候触发gc? jvm内存满了就触发,没满就不触发
                        3.gc机制会调用 Object 超类 的一个方法 finalize() 
        4.jvisualvm.exe -> 监视JVM的运行情况,从而发现gc,堆内存存在的问题

3.java的变量,数据类型等内容
    
    java的数据类型:
        1.基本数据类型
        2.引用数据类型

    基本数据类型:
        1.byte -> 1字节
        2.short -> 2字节
        3.int -> 4字节
        4.long -> 8字节
        5.float -> 4字节
        6.double -> 8字节
        7.char -> 2字节
        8.boolean -> 1字节
        
        java中的基本数据类型都是以补码(符号位不变,其他每一位取反后加1)的形式进行保存的

        基本数据类型传参:
            值传递

    引用数据类型:
        对象

        引用数据类型传参:
            地址传递

        面向对象(Object oritented programming):
            面向对象是一种编程思想,把现实生活中存在的一个个事物通过软件中对象的方式来进行表示

            现实中的事物:
                1.属性 -> 这个东西是什么  -> 成员变量
                2.行为 -> 这个东西可以干什么 -> 成员方法

        面向接口编程:
            把现实生活中的接口抽象化到软件中表示

            接口(规范):屏蔽掉接口双方的差异性

            举例:
                JDBC:
                    sun公司定义的一套关于java操作数据库的规范流程,所有的数据库厂商需要实现这个接口来完成驱动的编写,程序员只需要调用接口
                    即可完成数据库的操作
                    程序员不用关心数据库厂商到底怎么写的驱动,因为反正实现了JDBC的接口,肯定有实现类!
                    数据库厂商不用关心程序员到底怎么写的代码,反正你要调用JDBC的接口!

                    JDBC做了操作数据库的规范,代码里面需要切换一个数据库的话,只需要换一下加载的驱动即可!其他所有JDBC的代码都不用修改!
                    Class.forname("org.oracle.xxx");
                    Connecttion connection = DriverManager.getConnection();
                    PreparedStatement ps = connection.preparedstatement("select * from user");
                    ResultSet rs = ps.executeQuery();
                    while(rs.next()){
                        xxx
                    }
            
                SSM以及SpringBoot项目,service层和dao层接口:
                    interface UserService
                    class UserServiceImpl

                    1.dao层针对mysql和oracle可以写两个实现类,不破环以前代码的侵入性
                    2.接口对行为做了规范,在需求分析阶段:
                        1.设计数据库
                        2.设计接口
                            interface UserDao{
                                void addUser();
                                void updateUser(User user);
                                void delUser(int id);
                                xxx
                            }

                            Service层调用的时候,面向的是接口,不需要关注接口具体怎么实现的,反正接口的实现类要实现这个接口,肯定会有这个接口里面的
                            所有抽象方法

        面向对象三特性:
            1.封装
                封装就是将一个对象内部的属性隐藏起来,对外提供公共的方法进行访问和修改

                封装的意义:
                    1.保证对象内部的安全性,属性不能随意修改
                    2.可以在修改和访问属性的时候做额外的操作
                        public void setxxx(int age){
                            this.age = age;
                            sout("年龄修改为了xxx")
                        }
            2.继承
                继承:
                    对现实生活中的父子关系进行了抽象化

                在子类对象里面开辟一个父类空间,用来保存父类的相关信息
                如果要使用某个成员变量或者成员方法的时候,先去子类对象中找有没有,然后才去父类空间中找

                this -> 当前对象
                super -> 父类空间

                重载和重写:
                    重载:发生在同一个类里面,方法名相同,参数列表不相同,在调用者看来完全是两个不同的方法
                    重写:发生在父类和子类之间,父类和子类有完全一样的方法(方法名,参数列表完全一致),子类把父类的方法给掩盖起来


                子类会默认调用父类的无参构造,但是如果父类没有无参构造,必须在子类的构造方法里面手动调用父类的某一个构造方法


                this()和super()为什么必须写在第一行?
                    因为super()不写在第一行的话,相当于子类都开始执行方法了,父类空间还没生成

            3.多态
                多态:一个东西的不同表现方式
                运行时多态:
                    父类引用指向子类对象 向上转型 
                    Fu fu = new Zi() 

                    需要满足的条件
                    1.继承
                    2.子类重写父类方法
                    3.父类引用指向子类对象

                    1.对于成员变量而言,看的是父类的
                    2.对于成员方法而言,看子类的
                    3.对于静态而言,看父类的

                    举例:
                        花木兰替父从军
                编译时多态:重载

                多态的意义?
                    1.可扩展性,因为一个接口/类可能有很多的实现类/子类,使用多态的话就避免使用子类的特有的方法,
                    当需要切换一个实现类/子类使用的时候,避免修改以前的代码
                    2.灵活性

        字面值:
            指的是看见一个数据,就知道这个数据是什么样的数据类型 

            1.整形字面值:
                123 -> int
                123l -> long

            2.浮点数字面值:
                1.1/1.1d -> double
                1.1f -> float

            3.null字面值:
                空对象

            4.char字面值:
                'a' -> char
            
            5.boolean字面值:
                true -> boolean
            
            6.字符串字面值:
                "abc" -> string

            所有的字面值都是常量,都存放在常量池

            String为什么特殊,因为其他所有的引用数据类型都是通过new关键字创建出来的,只有string有字面值常量

            String:
                当使用到一个字面值常量的时候首先:
                    1.先去常量池里面找有没有这个对象存在
                    2.如果有:则直接将这个对象的地址赋值给变量
                      如果没有:先在常量池里面创建一个string对象,然后将这个对象的地址赋值给变量        

                String的特点:
                    1.可以被共享
                        String a = "abc"
                        String b = "abc"
                        a和b指向的是常量池里面的同一个对象

                    2.String本质就是一个char[]

                    3.string不可被修改,因为 char[]被 final关键字修饰

                String拼接运算符+本质是干什么事:
                    String a = "a"+new String("b");

                    1.创建一个临时的stringbuilder对象
                    2.调用stringbuilder的append方法进行拼接
                    3.调用stringbuilder的toString方法把stringbuilder变成一个普通的string

        数据类型转换:
            普通数据类型:
                自动类型类型转换:取值范围小的数据转化为取值范围大的数据 (本质就是前面添加0,对原本的值没有改变)
                强制类型转换:取值范围大的数据转化为取值范围小的数据 (把前面几个字节砍一刀,砍没了数据可能会改变)
            引用数据类型:  
                自动类型转换:子类类型转化成父类 向上转型  
                    为什么能自动完成?
                        因为子类一定包含了父类的信息!
                强制类型转换:父类类型转化成子类 向下转型
                    为什么必须强制完成?
                        因为父类中可能不包含子类的信息!

4.java的数组

    静态数组:
        三种定义方法

        1.数据类型[] 变量名 = new 数据类型[长度]
        
        2.数据类型[] 变量名 = new数据类型[]{数据1,数据2,xxxx}

        3.数据类型[] 变量名 = {数据1,数据2,xxxx}

    动态数组:
        Collection -> 表示的是一个抽象的概念 一个装东西的集合,单列集合
            1.set -> 无序,不可重复的集合
                实现类:hashSet:底层就用了hashmap
            2.list -> 有序,可重复的集合
                实现类:1.linkedlist -> 双向循环链表 
                        双向指的是每一个node 有两个属性 next 指向下一个节点 previous 指向上一个节点
                        循环:最后一个节点的next指向第一个节点

                        链表的特点:删除和增加元素很快,但是查找了修改很慢(因为地址不是连续的,我要访问到一个元素,必须从头开始遍历)
                        2.arrayList -> 动态数组
                        数组的特点:删除和增加元素很慢,但是查找了修改很快(因为数组的地址是连续的,通过索引的计算就可以直接算出元素的物理地址)

                        数组的地址:
                            第一个元素的地址

                            为什么java要把数组设计成只能保存一种数据类型?
                                因为方便通过 数组地址+索引*元素大小 来计算元素的实际物理地址

                        ArrayList的本质:
                            Object[]

                                虽然Object数组什么类型的数据都能存放,但是当数据保存在Object[]里面的时候,会向上转型,转化成Object类型
                                但是取出元素的时候,还是Object类型的数据,就必须进行强制类型转换,向下转型成子类类型

                            泛型:
                                泛型就是将 数据类型 作为参数 传递给一个类 (参数化类型)

                                将类型转换的操作 从运行阶段 提前到了编译阶段 

                                ps:java的泛型是伪泛型,编译以后会进行擦除,即把所有的泛型类型变成Object

                                ArrayList的扩容机制:
                                    通过无参构造创建出的arraylist 长度为 0
                                    第一次添加元素的时候,会把长度变为10
                                    以后每一次到达最大长度的时候会扩容 grow ,将长度变为以前的1.5倍 1+x>>1 1+0.5


        Map -> 双列集合 
                实现类:HashMap

                HashMap的结构:
                    数组+链表(单向的链表) 每个键值对 Node节点的对象来表示

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

        Node(int hash, K key, V value, Node<K,V> next) {
            this.hash = hash;
            this.key = key;
            this.value = value;
            this.next = next;
        }

        public final K getKey()        { return key; }
        public final V getValue()      { return value; }
        public final String toString() { return key + "=" + value; }

        public final int hashCode() {
            return Objects.hashCode(key) ^ Objects.hashCode(value);
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final boolean equals(Object o) {
            if (o == this)
                return true;
            if (o instanceof Map.Entry) {
                Map.Entry<?,?> e = (Map.Entry<?,?>)o;
                if (Objects.equals(key, e.getKey()) &&
                    Objects.equals(value, e.getValue()))
                    return true;
            }
            return false;
        }
    }

                        为什么要使用hashmap?
                            因为hashmap结合使用了数组和链表 所以可以保证 CRUD的速度都比较快

                        HASH函数/散列函数:
                            将key和数组的index做一个联系,从而很快速的将Node插入到数组里面去

                            hash(key) = index

                            hash函数的意义就在于将元素平均分布到数组中保存(保证每个索引存在数据的概率是一样的)                            

                        hash冲突:
                            equals结果为false的两个对象,经过hash函数计算以后,得到了一样的hash值  

                        HashMap保存元素的过程:
                            1.保存一个键值对的时候,首先把这个键值对构建为一个 静态内部类 Node 的对象
                            2.计算hash函数 将 key 经过 hashmap 的一个静态方法 int hash(Object key)  来计算这个键值对的 index索引

                            static final int hash(Object key) {
                                 int h;
                                return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
                             }
                            
                            (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16) -> 可以得到结论如下:
                                1.hashmap可以保存null键 如果键是null的话 得到的索引为0 把这个键值对放到数组的第一个元素的位置
                                2.hashmap通过调用键对象的hashcode()方法来计算索引值 计算过程是 右移十六位和以前的hashcode做异或(二进制位上相同位0,不相同位1)
                                3.hashcode()函数是 object超类提供的 
                                    为什么重写了equals方法必须重写hashcode()方法?
                                        equals()方法 -> java官方的定义:判断两个对象是否相等

                                        equals相同的两个对象绝对有相同的hashcode

                                        1.但是如果重写了equals,但是没有重写hashcode的话,可能会出现
                                        equals结果为true的两个对象有不同的hash值

                                        2.还会导致hashmap不可用

                                            因为equals的结果为true的话,证明是同一个对象,放在数组的同一个位置
                                            但是如果没有重写hashcode的话,会出现:
                                                
                                            class Student{
                                                int age;

                                                public boolean equals(Student student){
                                                    return this.age=student.age?true:false;
                                                }
                                            }

                                            Student student1 = new Student();
                                            Student student2 = new Student();

                                            hashmap.put(student1,1)
                                            1.计算student1的hash值 为 1
                                            2.把student1这个键值对放到数组的 第二个位置
                                            hashmap.put(student2,2)
                                            1.计算student2的hash值 为 1

                                            hashmap.get(student2)
                            3.计算hash值以后,查看数组位置上是否有元素,如果没有元素的话,直接放进去
                                如果有元素的话,把这个元素的 key拿出来 和这个键值对的key 用equals方法进行比较 如果结果为true 就替换掉以前的值
                                    如果equals的结果为false 在后面添加链表     

                        HashMap的扩容机制:
                            1.初始长度是16,最大长度是 2的30次方 长度必须是2的N次幂
                            2.负载因子:
                                数组最多能保存 长度*负载因子 个元素 默认的负载因子是 0.75
                                
                                如果负载因子过小的话:会频繁扩容,影响效率
                                如果负载因子过大的话:链表长度过长,影响效率
                            3.如果达到数组最大程度的话(长度*负载因子),就会进行扩容,数组长度扩大为以前的两倍,会重新再hash(因为再hash很花时间,所以应该尽量避免hashmap扩容)
                            4.如果数组长度大于等于64,链表长度大于等于8的时候,数组+链表就会变成红黑树 进一步增加效率
                            
5.Object
    Object超类是所有对象的公共父类

    Object:
        1. public final native Class<?> getClass(); -> 返回一个对象的Class对象

            3个方法获得类对象:
                1.Class.forname("类的全限定名称") 
                    全限定名称就是 包名.包名.包名.xxx.类名 比如 com.mysql.jdbc.Driver
                2.通过类名.class 
                3.通过对象的 getClass方法 

        2. public native int hashCode(); -> 将对象的物理地址转化为了整形数字

        3.  public boolean equals(Object obj) {
        return (this == obj);
    }  -> 1.==和equals的区别  用于判断两个对象是否相等

          2.为什么重写equals方法要重写hashcode 
            1.因为如果不重写hashcode 可能会出现 两个相等的对象 有 不一样的hash值
            2.如果不重写的话,hashmap不可用

        4. protected native Object clone() throws CloneNotSupportedException; -> 克隆 复制一份当前对象的拷贝 

            深拷贝和浅拷贝:
                浅拷贝:复制出来的对象在新的地址里,但是里面的引用数据类型和以前的对象一样

                深拷贝:复制出来的对象和以前的对象没有任何关系
        5.public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    } -> 将对象转化成字符串

        6.protected void finalize() throws Throwable { } -> 如果你要自定义销毁对象时触发的函数,需要重写这个方法

            gc时会调用

            

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值