前言

上学期Java没好好学,重新学习下,定期学完整理下笔记,做个总结。

  • 如果有错误欢迎指出

编译流程

.java -> .class -> 执行.class

缩写全称英文全称解释
jvmJava虚拟机Java virtual machine
jreJava运行环境Java runtime environmentjvm + 核心类库
jdkJava开发工具包Java development kitjre+运行环境工具

jvm < jre < jdk

创建String流程

  • 两种方式创建区别

      String a = "hello";
      String b = "hello";
      System.out.println(a==b);
    
      String c = new String("hello");
      String d = new String("hello");
      System.out.println(c==d);
      true
      false

原因分析

虚拟机内存划分(涉及本次)

区域包括
方法区常量池,静态变量等
基本类型,引用类型
对象的实例(new)

对于栈和常量池中的对象可以共享,对于堆中的对象不可以共享。栈中的数据大小和生命周期是可以确定的,当没有引用指向数据时,这个数据就会自动消失。堆中的对象的由垃圾回收器负责回收,因此大小和生命周期不需要确定,具有很大的灵活性。
而对于字符串来说,其对象的引用都是存储在栈中的,如果是编译期已经创建好(即指用双引号定义的)的就存储在常量池中,如果是运行期(new出来的对象)则存储在堆中。对于equals相等的字符串,在常量池中是只有一份的,在堆中则有多份。

创建 String,先在 常量池中寻找,如果有,则直接使用,如果无,则创建后放入 常量池,并使用

  1. 使用 String str = ""创建在 中创建 str,指向 常量池(如果 常量池中无则创建,否则直接使用)
  2. 使用 new创建在 中创建一个 常量池对象的拷贝对象(如果 常量池中无则创建,否则直接使用)。中创建 引用指向 中拷贝对象。
  3. 区别:

    1. 如果使用字面量,则从 常量池中找
    2. 如果使用 new,则从 中创建,而 又会从 常量池中找
    3. 如果想 new后从 常量池中获取,可以使用 inter()。如上代码。
      System.out.println(c.intern() == a); true

例题:

  • String str = new String("hello")创建了多少个对象?

    1. 如果 常量池中不存在:则产生2个 对象和1个 引用
    2. 如果之前存在,则产生1个 对象和1个 引用
  • String str = new String("a" + "b")产生多少个对象?(常量池为空,不含引用)4个 (常量池中)a + b + ab + 堆中1个
  • String str = new String("a") + "a"产生多少个对象?(常量池为空,不含引用)
    3个 (常量池中)a + aa + 堆中1个

访问修饰符

访问修饰符本类同包子类其他
private
默认
protected
public

继承/代码块/重写和重载

  • 子类继承父类:private,构造方法 是不能被继承的。但是 子类可以调用父类构造 super
  • 代码块:

    1. 静态代码块:永远只执行一次。初始化。
    2. 普通代码块:每次在 被创建之前执行。
    3. 执行顺序:

      1. 父类static
      2. 子类static
      3. 父类普通
      4. 父类构造
      5. 子类普通
      6. 子类构造

重写和重载(Override/Overload)

位置方法名参数表返回值访问修饰符
方法重写子类相同相同相同或者是其子类不能比父类更严格
方法重载同类相同不相同无关无关

抽象类/final

抽象类

class abstract t {
    public abstract void a();
}
  • 抽象类不能被实例化,因为可能存在 抽象方法,而 抽象方法没有 方法体
  • 抽象方法必须在 抽象类中。
  • 抽象类中,并不一定包含 抽象方法

final

修饰对象限制
不能被继承
方法不能被重写
变量不能被修改

多态

父类 引用对象名 = new 子类()`double d = 10 //大范围类型 = 小范围类型`

  • 多态实现方法:

    1. 方法重载
    2. 方法重写
    3. 使用 父类作为方法的 形参
    4. 使用 父类作为方法的 返回值
  • 判断父子类:对象 instanceof 类型

接口

public interface Person {
    //1.属性全部是static final类型
    //2.方法全是public abstract
    void a();
    int b();
}

接口抽象类 更进一步 "抽象"

  • 继承:is a接口:has a
  • 父类 -> 子类 -> A extends B{}接口 -> 实现类 -> A implements B{}
  • 类:单继承;接口:接口之间可以相互继承,多继承。
  • 接口不存在 构造方法
  • 实现 接口的时候,类要实现接口中所有的方法。否则,类必须声明为抽象的类。
  • 接口回调:以后填坑。

值传递/引用传递

  • 基本类型作为参数传递,值不变。
  • 引用类型作为参数传递,值改变。

Lambda入门(Java8)

  • 作用:简化代码
  • 组成:

    • 逗号隔开的参数列表(a, b, c)
    • 箭头符号 ->
    • 方法体(λ代码块)
  • 要求重写的 接口,抽象类中 有且只有一个 抽象方法
  • 函数式接口:@FunctionalInterface 有且只有一个抽象方法
  • lambda 表达式只能引用标记了 final 的外层局部变量,这就是说不能在 lambda 内部修改定义在域外的局部变量,否则会编译错误。
  • 如果主体包含了一个语句,就不需要使用大括号。也不需要引号
    public static void main(String[] args) {
        new Thread(
                () -> System.out.print("hello")
        ).start();
    }

内部类

套娃有点脑壳痛QAQ

分类:

  • 成员内部类

    • 内用外,随意
    • 外用内,需要内部类对象
    • 外部类名称.内部类名称 对象名 = new 外部类名称().内部类名称();
  • 局部内部类

    • 定义在方法内部

      class name {
          //没有权限修饰符
      }
  • 匿名内部类

    • 实现:

      new Interface()  {
      // Anonymous  class body  goes  here
      }
    • 接口名 就是 匿名内部类要实现哪个 接口
    • 创建的 只能使用一次。

多线程

创建线程:

都要重写 run方法

  1. MyThread继承Thread(本质也是实现Runnable)

    public class tmp {
        public static void main(String[] args) {
            MyThread m = new MyThread();
            m.start();
        }
    }
    
    class MyThread extends Thread {
        public void run() {
            // TODO Auto-generated method stub
            System.out.print("hello");
        }
    }
  2. 实现Runnable接口

    public class tmp {
        public static void main(String[] args) {
            dou d = new dou();
            Thread t = new Thread(d);
            t.start();
        }
    }
    
    class dou implements Runnable {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            System.out.print("hello");
        }
    }

线程同步

  • 多线程访问了共享的数据,会产生线程安全问题。
  • 如何解决:

    • 同步代码块

      Object obj = new Object()
      synchronized(obj) {
          //访问共享数据的代码
      }
    • 同步方法

      public synchronized void payTicket() {
          if()
              //卖票
      }
    • 锁机制

      private final ReentrantLock lock = new ReentrantLock();
      
      public void demo() {
          lock.lock();
          try {
      
          } finally {
              lock.unlock();
          }
      }

异常

exp

  • 运行时异常:代码在编辑时,不报错,运行时才报错。语法上,可选择处理。
  • 检查异常:代码在编辑时,报错。编辑时必须处理。
  • 关键字:try catch finally throws throw
  • 如果 try中出现异常,则跳过异常后代码,跳转到 catch

try catch

当前方法能够处理。

throws

当前方法不能处理,上交到 方法调用处 处理。

  • main函数 再向上抛出 给 JVM

finally

无论正常,异常,始终执行的代码。

  • 即使遇到return,也会执行。
  • 除非虚拟机关闭,不会执行。
    System.exit(0)是正常退出程序,而System.exit(1)或者说非0表示非正常退出程序

throw

声明异常
throw new MyException("msg");

自定义异常

  • 继承Exception,调用 Super(msg)

常用方法

  • e.printStackTrace();
  • e.getMessage();



扫一扫在手机打开当前页