【笔记】JAVA SE

【笔记】JAVA SE

1.快捷键

Ctrl + Y 反撤销

2.DOS命令

命令说明
e:切换盘符,进入e盘
dir展现指定目录下的所有子文件和子目录
cd进入目录
cd .访问当前目录
cd …退到上层目录
cd /退到根目录
cls清空屏幕
exit退出dos命令行
mkdir新建目录
rmdir删除目录,要求删除的目录必须为空
del删除文件
notepad打开记事本

3.JDK,JRE和JVM之间的关系

  • JDK(Java Development Kit)JDK是Java开发工具包,是整个Java的核心,包括了Java运行环境JRE、Java工具和Java基础类库
  • JRE(Java Runtime Enviroment)JRE是java的运行环境,包含JVM标准实现及Java核心类库
  • JVM( java virtual machine)JVM是java虚拟机,是整个java实现跨平台的最核心的部分,能够运行以Java语言写作的软件程序

三者的关系:
JDK = JRE + 其他
JRE = JVM + 其他
总的来说 JDK 是用于 java 程序的开发,而jre则是只能运行 class 而没有编译的功能,Eclipse、IntelliJ IDEA 等其他 IDE 有自己的编译器而不是用 JDK bin 目录中自带的,所以在安装时只选中 jre 路径就可以

4.JDK的主要文件夹说明

  • bin:最主要的是编译器(javac.exe)
  • db:jdk从1.6之后内置了Derby数据库,它是一个纯用Java实现的内存数据库,属于Apache的一个开源项目。用Java实现的,所以可以在任何平台上运行;另外一个特点是体积小,免安装,只需要几个小jar包就可以运行
  • include:java和JVM交互用的头文件
  • lib:常用类库
  • jre:java运行环境

5.JVM的内存分配

在这里插入图片描述

JVM基本概念:
JVM 是可运行 Java 代码的假想计算机,包括一套字节码指令集、一组寄存器、一个栈、一个垃圾回收、一个堆和一个存储方法域。
JVM 是运行在操作系统之上的,它与硬件没有直接的交互

JVM内存划分:
拥有五类(直接内存除外):

  • 程序计数器:
    是每个线程都拥有的一块空间,线程私有,存储当前线程执行的字节码所在的行号指示器,执行方法时,计数器存储执行位置(对应字节码指令位置),代表了方法的执行位置

  • 本地方法栈:
    是与对应的操作系统 OS 进行操作的方法的集合,是每个线程都拥有的,为调用 native 服务而存在

  • 方法区:
    又称为永久代,是线程共享的,存储 JVM 的类加载信息(类的方法、版本、时间、方法和接口等),常量,静态变量,(非 new 对象)编译器产生的字节码文件内容
    运行时常量池是它的重要组成部分,存储了在编译时产生的各种变量字符引用信息,通常在类加载完成后进行存储,是 JVM 认可类的主要信息标准

  • 堆:
    Heap 属于运行时内存,被线程共享,存放被 java 程序通过 new 关键字得到的对象,如数组、哈希表和自定义类等,是GC( Garbage Collection)的重要区域
    在 java 的 GC 中,将此区域按代划分,可分为新生代(存放 new 对象,过大的对象除外)和老年代(存放已被创建一段时间的 new 对象),新生代占 1/3 区域,老年代占 2/3 区域
    新生代又可细分为

    • Ende:当此区域不足时,新生代自动开启一次 GC,当被创建对象过大的时候,直接放入 Old 区
    • From Survivor:上次回收时的新村对象
    • To Survivor:时上次复制的幸存对象,年龄足够就会被存入老年代
  • 虚拟机栈
    是线程私有的,用于描述方法执行的内存模型
    在线程执行方法时,会创建一个栈帧并入栈,在方法执行完后,将对应栈帧出栈
    栈帧包含了:

    • 方法局部变量表:方法内变量,执行结束后就销毁
    • 操作数栈:计算方法执行过程产生的结果
    • 动态链接:存储常量池的指针,方便方法动态访问常量池
    • 方法出口(返回地址):当方法正常结束或者异常结束后,都需要依靠此信息返回对应信息,以便程序能继续执行

栈帧示意图:
在这里插入图片描述

6.Java中的堆和栈的关系

先看一个由 C/C++ 编译的程序占用的内存分为以下几个部分

  • 栈区(stack):
    由编译器自动分配释放,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈
  • 堆区(heap):
    由程序员分配释放,若程序员不释放,程序结束时可能由 OS 回收
    注意:它与数据结构中的堆是两回事,不过分配方式确实类似于链表
  • 全局区(静态区)(static):
    全局变量和静态变量的存储时放在一块的,初始化的全局变量和静态变量在同一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放
  • 文字常量区:
    常量字符串就是放在这里的,程序结束后由系统释放
  • 程序代码区:
    存放函数体的二进制代码

下面是如何在栈中创建对象的示例:

void somefunction(){
            /**创建 Member 类成员的 "m" 对象
             * 它将被放在栈上
             * 我们没有使用 "new" 关键字
             * 在汉神创建对象
             * */
            
            Member m;
}//一旦函数结束,对象 "m" 将被销毁

下面是如何在堆中创建对象的示例:

void somefunction(){
            /**创建 Member 类成员的 "m" 对象
             * 这将被放在堆上
             * 我们使用 "new" 关键字
             * 在函数内创建对象*/

            Member* m = new Member();
            
            /**对象 "m" 必须被删除
             * 否则会发生内存泄漏
             * */
            
            delete m;
}

Java 中的栈
Java 的栈时计算机内存的一部分,其中存储由程序员编写的所有函数所创建的临时变量。它用于执行线程,并且可能具有某些短生命周期的值以及对其他对象的引用。它使用 LIFO(后进先出)的数据结构

当一个方法被调用时,它会为该特定方法在堆栈中创建一个新的块。新块将具有所有局部变量,以及对该方法正在使用的其他对象的引用。当方法结束时,新的块将被擦除,并且可以被下一个方法使用。在这里找到的对象只能访问该特定函数,不能超越它

这使得跟踪栈非常容易,最新的保留快也是首先被释放的。为方法创建的变量直接存储在内存中,可以快速访问

Java 栈的内存大小通常远小于 Java 堆,因此当一个方法结束时,栈上创建的所有变量将永远被删除

Java 中的堆
Java 对象位于一个称为堆的区域中。它是程序运行时创建的,并且其大小可能随程序运行而减小或增加。它可以很容易地填满,当遇到类似堆满地情况时,垃圾回收机制会被触发。即当不再使用的对象被删除后,就是为新对象腾出空间的时候

与 Java 栈在编译程序时完成内存分配不同,使用堆时,内存分配是在运行程序的时候完成的。访问放置在堆上的变量相较栈的直接和快速访问有点慢

堆跟全局内存池有些类似。如果需要使用数据或变量的生命周期长于相关的方法或函数,方法或函数将使用堆进行内存分配。你在堆上获得的对象是可以被所有函数访问的

此外,在堆的保留块中没有特定的顺序。你可以随时分配块,然后你可以随意释放它。因此跟踪和分配相比栈复杂得多,但是可以通过分区的方式来改善

这些分区被称为新生区(或苗圃)和旧空间。新生区通常用于新对象的内存分配。当新生区满了,垃圾回收机制就会被触发。通常是短暂的或临时的物体使用新生区

堆和栈之间的相似与差异
两者都是 Java 内存分配的方式,并且都存储在 RAM 中

  • 为了更容易记忆,堆用于动态内存分配,而栈用于静态分配
  • 在栈中分配的变量可直接从内存访问,因此这些变量可以运行得非常快。另一方面,访问堆中的对象需要更多的时间
  • 分配内存:在栈中,当程序被编译时分配内存。而在堆中,则是开始于运行时
  • 如果要使用栈,则需要知道在编译之前需要多少数据和内存。栈的另一个限制是它不能处理需要大量内存的大块变量。如果不知道运行时需要多少数据,或者需要大量数据则要使用堆

简而言之:
栈:

  • 栈的大小会随着方法或函数的增删局部变量而按需变化
  • 内存会自动释放,无需管理内存分配
  • 栈的大小有限制,根据你所使用的操作系统而定
  • 存储在栈中的变量一直存在,只要创建它们的函数在运行

堆:

  • 内存不是自动管理的,也不是由中央处理器像栈那样严格管理。当这些块不再需要时,需要自己释放已分配内存
  • 堆容易出现内存泄漏,即当内存被分配给未使用的对象,且对其他进程则不可用
  • 堆没有大小限制
  • 与栈相比,堆中的对象访问起来慢得多,堆内存中的写操作也比较慢

栈使用起来更简单、更快捷,但它有许多限制,如果使用堆,你可以忽略那些限制

使用栈和堆的时机:

  • 栈:栈只能用于局部变量,使用少量的内存。好消息是内存分配和管理不会成为问题,对这些对象的访问非常快。它的大小确实受到限制,事实上你也不能调整栈的变量的大小
  • 堆:如果存在需要全局访问的变量,而不需要仅对创建它的方法和函数可用,则使用堆来分配内存。当你需要大量的内存,堆也是不错的,因为它对内存大小没有限制,你还可以调整堆变量的大小

7.重写和重载的区别

重写(Override)

从字面上看,重写就是 重新写一遍的意思。其实就是在子类中把父类本身有的方法重新写一遍。子类继承了父类原有的方法,但有时子类并不想原封不动的继承父类中的某个方法,所以在方法名,参数列表,返回类型(除过子类中方法的返回值是父类中方法返回值的子类时)都相同的情况下, 对方法体进行修改或重写,这就是重写。但要注意子类函数的访问修饰权限不能少于父类的

例如:

public class Father {

    public static void main(String[] args) {
        Son s = new Son();
        s.sayHello();
    }

    public void sayHello() {
        System.out.println("Hello");
    }
}

class Son extends Father{

    @Override
    public void sayHello() {
        // TODO Auto-generated method stub
        System.out.println("hello by ");
    }

}

简而言之:

  1. 发生在父类与子类之间
  2. 方法名,参数列表,返回类型(除非子类中方法的返回类型是父类中返回类型的子类)必须相同
  3. 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)
  4. 重写方法一定不能抛出新的检查异常或者比被重写方法申明更加宽泛的检查型异常

重载(Overload)

在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同甚至是参数顺序不同)则视为重载。同时,重载对返回类型没有要求,可以相同也可以不同,但不能通过返回类型是否相同来判断重载。

例如:

public class Father {

    public static void main(String[] args) {
        Father s = new Father();
        s.sayHello();
        s.sayHello("wintershii");

    }

    public void sayHello() {
        System.out.println("Hello");
    }

    public void sayHello(String name) {
        System.out.println("Hello" + " " + name);
    }
    
}

简而言之:

  1. 重载Overload是一个类中多态性的一种表现
  2. 重载要求同名方法的参数列表不同(参数类型,参数个数甚至是参数顺序)
  3. 重载的时候,返回值类型可以相同也可以不相同。无法以返回型别作为重载函数的区分标准

总结

方法的重载和重写都是实现多态的方式,区别在于前者实现的是编译时的多态性,而后者实现的是运行时的多态性。重载发生在一个类中,同名的方法如果有不同的参数列表(参数类型不同、参数个数不同或者二者都不同)则视为重载;重写发生在子类与父类之间,重写要求子类被重写方法与父类被重写方法有相同的参数列表,有兼容的返回类型,比父类被重写方法更好访问,不能比父类被重写方法声明更多的异常(里氏代换原则)。重载对返回类型没有特殊的要求,不能根据返回类型进行区分

8.抽象类和接口的区别

概念上的区别:

抽象类是对一种事物的抽象,即对类的抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性和行为,但是接口只是对类的局部(行为)进行抽象。举个简单的例子,飞机和鸟是不同类的事物,但是它们都有一个共性,就是都会飞。那么在设计的时候,可以将飞机设计为一个类 Airplane,将鸟设计为一个类 Bird,但是不能将飞行这个特性设计为一个类,因为它只是一个行为特性,并不是对一类事物的抽象描述。此时可以将飞行设计为一个接口 Fly,包含方法 fly(),然后 Airplane 和 Bird分别根据自己的需要实现 Fly 这个接口。对于不同种类的飞机,比如直升机,、战斗机和民航等直接继承 Airplane 即可。从这里可以看出,继承是一个“是不是”的关系,而实现接口则是“有没有”的关系。如果一个类继承了某个抽象类,则子类必定是属于抽象类的“种类”,而实现接口则是有没有、具不具备的关系

语法层面上的区别:

  1. 抽象类可以有构造方法,接口中不能有构造方法
  2. 抽象类中可以有普通成员变量,接口中没有普通成员变量
  3. 抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法
  4. 抽象类中的抽象方法的访问类型可以是 public 和 protected,但接口中的抽象方法只能是 public类型的,并且默认为 public abstract
  5. 抽象类中可以包含静态方法,接口中不能包含静态方法
  6. 抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型是任意的,但接口中定义的变量只能是 public static final 类型,并且默认为 public static final
  7. 一个类可以实现多个接口,但只能继承一个抽象类

设计层面上的区别
对于抽象类,如果需要添加新的方法,可以直接在抽象类中添加具体的实现,子类可以不进行变更;而对于接口则不行,如果接口进行了变更,则所有实现这个接口的类都必须进行相应的改动

应用层面上的区别
接口更多的是在系统架构设计方法发挥作用,主要用于定义模板之间的通信契约。而抽象类在代码实现方面发挥作用,可以实现代码的重用,例如,模板方法设计模式是抽象类的一个典型应用,假设某个项目的所有 Servlet 类都要用相同的方式进行权限判断、记录访问日志和处理异常,那么就可以定义一个抽象的基类,让所有的 Servlet 都继承这个抽象基类,在抽象基类的 service 方法中完成权限判断、记录访问日志和处理异常的代码,在各个子类中只是完成各自的业务逻辑代码

门和警报的例子:门都有 open() 和 close() 两个动作,此时我们可以通过抽象类或接口来定义这个抽象概念:

abstract class Door{
    public abstract void open();

    public abstract void close();
}
interface Door{
    public abstract void open();

    public abstract void close();
}

现在如果我们需要门具有报警功能,那么该如何实现?下面提供两种思路:

  1. 将这三个功能都放在抽象类里面,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是有的门并不一定具备报警功能;
  2. 将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的 open() 和 close(),也许这个类根本就不具备 open() 和 close() 这两个功能,比如火灾报警器

从这里可以看出,Door 的 open()和close() 与 alarm() 根本就属于两个不同范畴内的行为,open() 和 close() 属于门本身固有的行为特性,而 alarm() 属于延伸的附加行为。因此最好的解决办法是单独将报警设计为一个接口,包含 alarm() 行为,Door 设计为单独的一个抽象类,包含 open 和 close 两种行为。再设计一个报警门 继承 Door 类并实现 Alarm 接口

interface Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

9.length() 方法,length 属性和 size() 方法的区别

  • length() 方法是针对字符串来说的,要获得一个字符串的长度就要用到它的 length() 方法
  • length 属性是针对 Java 中的数组来说的,要获得数组的长度可以用其 length 属性
  • Java 中的 size() 方法是针对泛型集合说的,如果想看这个泛型有多少个元素,就调用此方法查看

实例:

import java.util.ArrayList;
import java.util.List;

public class Main {

    public static void main(String[] args) {
        String array[] = { "First", "Second", "Third" };
        String a = "HelloWorld";
        List<String> list = new ArrayList<String>();
        list.add(a);
        System.out.println("数组array的长度为" + array.length);
        System.out.println("字符串a的长度为" + a.length());
        System.out.println("list中元素个数为" + list.size());

    }
}

运行结果为:

数组array的长度为3
字符串a的长度为10
list中元素个数为1

10.JAVA有六个地方可以存储数据

  • 寄存器: 最快的存储区,位于不同于其它存储区的地方——处理器内部。寄存器的数量极其有限,所以寄存器由编译器根据需求进行分配。你不能直接控制,也不能在程序中感到寄存器存在的任何迹象
  • 栈: 存放基本类型的变量数据和对象的引用。位于通用 RAM 中,但通过它的 ”堆栈指针“ 可以从处理器获得支持。堆栈指针若向下移动,则分配新的内存;若向上移动,则释放那些内存。这是一种快速有效的分配存储方法,仅次于寄存器。创建程序时,JAVA 编译器必须知道存储在堆栈内所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针,这一约束限制了程序的灵活性
  • 堆: 一种通用性的内存池(也存在于 RAM 中),用于存放所有的 JAVA 对象。堆不同于堆栈的好处是:编译器不需要知道要从堆里分配多少存储区域,也不必知道存储的数据在堆里存活多长时间。因此,在堆里分配存储有很大的灵活性。当你需要创建一个对象的时候,只需要 new 写一行简单的代码,当执行这行代码时,会自动在堆里进行存储分配。当然,为了这种灵活性,必须要付出相应的代码。用堆进行存储分配比用栈进行存储分配需要更多的时间
  • 静态域: 存放静态成员
  • 常量池: 存放字符串常量和基本类型常量(public static final)常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变
  • 非 RAM 存储: 硬盘等永久存储空间。如果数据完全存活于程序之外,那么它可以不受程序的任何控制,在程序没有运行时也可以存在

栈和常量池中的对象可以共享,堆中的对象不可以共享
栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会消失
堆中的对象由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性

11.Collection常用实现类对比

List 接口是一个有序,元素可重复的 Collection,使用此接口能够精确地控制每个元素插入的位置,能够通过索引(元素在 List 中的位置,类似于数组的下标)来访问 List 中的元素,第一个元素的索引为 0,而且允许有相同的元素

  • ArrayList
    底层数据结构是数组,查改快,增删慢
    非线程安全,效率高
  • Vector
    底层数据结构是数组,查改快,增删慢
    线程安全,效率低
  • LinkedList
    底层数据结构是链表,查改慢,增删快
    非线程安全,效率高

Set 接口存储一组唯一,无序的对象

  • HashSet
    底层数据结构是哈希表(无序,唯一)
    依赖两个方法:hashCode() 和 equals() 保证元素唯一性
  • LinkedHashSet
    底层数据结构是链表和哈希表(FIFO 插入有序,唯一)
    Linked:由链表保证元素有序
    Hash:由哈希表保证元素唯一
  • TreeSet
    底层数据结构是红黑树(唯一,有序)
    通过自然排序和比较器排序保证元素排序
    在这里插入图片描述

12.Map常用实现类对比

  • HashMap
    无序,非线程安全,效率高,允许 null 值(key 和 value 都允许)
  • Hashtable
    无序,线程安全,效率低,不允许 null 值
    除构造函数外,所有的 public 方法声明中都有 synchronized 关键字
  • TreeMap
    有序,非线程安全,效率高(O(logN)),但比不上 HashMap(O(1))

13.未完待续……

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

313YPHU3

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值