Java笔记

Java背景

1. 官网

2. java和JVM

  • java是基于类的、纯粹的面向对象编程语言

  • java是解释执行类的语言

  • WORA(write once, run anywhere)

    • java程序被称之为一次写入,到处运行
    • 只要系统上有JVM,就能运行java程序
  • 相关

    • .java - java的源码文件

    • javac - java的编译器

    • .class - 编译后的二进制数据文件

3. java版本

3.1 平台体系

  1. Java SE(Java Platform Standard Edition)。Java SE 以前称为 J2SE。它允许开发和部署在桌面、服务器、嵌入式环境和实时环境中使用的 Java 应用程序。
  2. Java EE(Java Platform Enterprise Edition)。这个版本以前称为 J2EE。 开发企业级的应用
  3. Java ME(Java Platform Micro Edition)。这个版本以前称为 J2ME。Java ME 为在移动设备和嵌入式设备(比如手机、PDA、电视机顶盒和打印机)上运行的应用程序提供一个健壮且灵活的环境.

3.2 JDK和JRE

  • JDK - java development kit,java开发包,包含java开发工具和JRE

  • JRE - java runtime environment, java运行时环境,包含java虚拟机和运行时库

  • 场景

    • 开发 - JDK

    • 运行 - JRE

3.3 历史版本

至本文档编写时,JAVA已经推出JDK20,但现在广泛使用的版本是JAVA8,官网上所显示的LTS版本如下

版本 维护时间
JDK8 2030.09
JDK11 2026.09
JDK17 2024.09 后续每年会有LTS

所以,没有特别的需求,JDK8就满足需求。

3.4 Oracle JDK和OpenJDK

  • Oracle JDK - 甲骨文收购了java后,维护的java版本,不开源

  • OpenJDK

    • 甲骨文开源的java版

    • 各公司使用这个版本进行二次开发得到自己的JDK,比如安卓的ART

    • 去除了很多JAVA的类库,保留核心功能,相当于纯净版Java

3.5 环境配置

4. jar包

java的执行有两种方式:

  • 执行源码
  • 执行编译后程序

Java编译后的程序后缀名为.jar, 也被称为jar包

4.1 打包

  1. 打开File->Project Structur

  2. 选择Artifacts,点击+,选择jar->From Modules xxxx

  3. 选择主类,点击Main Class后的图标,完事后点击OK

  4. 回到主界面,菜单build->build Artifacts,确认完成打包

4.2 执行

执行默认的类

java -jar xxxx.jar

指定主类执行

java -cp xxx.jar 包名.类名

4.3 引入第三方jar包

  1. 打包一个jar包,不同的地方是选择empty
  2. 主程序创建一个文件夹libs,然后将之前打包的jar包拷贝过来
  3. Project structure中的module中将本地jar包导入
  4. 创建artifacts,流程和之前的一样

Java语言

1. java语法

java语法与c++语法高度相似,故本课程对于相同点只列出相关语法,对于不同点会详细讲解。

2. 基本数据类型

java并不像c++那样继承了c语言的"丰富"的数据类型,java只有有符号数据类型。

基本数据类型 大小 取值
boolean true,false
byte 1 字节
char 2 字节
short 2 字节
int 4 字节
long 8 字节
float 4 字节
double 8 字节
void

2.1 var

  • java的auto,用于定义局部变量

2.2 final

  • 格式 [访问权限] final 数据/方法/类
  • final类似于C++中的finalconst的结合
  • final拥有更广泛的应用范围, 可修饰数据, 方法和类
  • final修饰后, 会具有不可变
    • 不可变 一旦初始化就不能被修改, 不会被编译器优化
    • 常量 可以被编译器优化
修饰 意义 示例
基本数据类型 不可修改 private final int n = 0;
类类型 对象可以修改,不可再指向别的对象 private Foo final foo = new Foo();
方法 不可被覆盖 public final void Foo(){}
不可被继承 final class Foo{}
静态数据 可当做常量 public static final int VAL = 0;

3. 运算符

java的运算符基本上与c++的是一样的。

java没有sizeof

分类 运算符
赋值 =
算术 +-*/%``+=-=*=%=``++--
关系 ><<= >=!===
逻辑 &&,`
位操作 &,`
三目 ?:
类型转换(强转) (新类型)原类型

4. 流程控制

流程控制和c++是一样的。

分类 运算符
分支 if-else``if-else if-else``switch-case
循环 while``do-while``for``for(范围迭代)``break``continue
goto

4.1 switch语句

  • java中的switch除了提供传统的分支流程控制功能外,还可以作为一种升级版的三目,即提供多重选择

  • 语法

    • case标签

      • 类型为char、byte、short或int的常量表达式

      • 枚举常量

      • 字符串字面量

      • 多个字符串,用逗号分隔

    • yield 关键字 - 用于返回赋值给变量的值。

// 形式1
变量 = swith(选择){
    case 值 -> 表达式;
    case 值 -> 表达式;
    case 值 -> 表达式;
    default ->表达式;
};
// 形式2
变量 = swith(选择){
    case 值 -> {  表达式; yield 值;}
    case 值 -> {  表达式; yield 值;}
    case 值 -> {  表达式; yield 值;}
    default -> {  表达式; yield 值;}
};

5. 代码组织结构

  • java程序逻辑上以包为单位
  • 一个包中包含多个类

  • 源码结构

    • 包名作为路径名

    • 类名作为文件名

  • 图示解析

    • java的包名类似c++的命名空间,但不同的是,java的包名既是空间名,也是路径名

    • 下面的程序中有两个包名,也就有两个路径

      • /com/kr/base - 有两个文件

        • Foo.java

        • Test.java

      • /com/kr/core - 有两个文件

        • Foo.java

        • Test.java

6. 类

6.1 格式

java的类与c++的类在语法上大体相同,区别在于访问权限需要写在java的类和成员前面。

  • 构造与类名相同,不需要析构

  • 成员函数可以重载

  • 访问权限 ,可选

    • public

    • private

    • protected

  • 成员函数同样有this指针

  • 静态成员 - 属于类,而非对象

[访问权限] class 类名{
	[访问权限] 成员;
	[访问权限] 成员;
	[访问权限] 成员;
    [访问权限] 成员;
    [访问权限] 成员;
    ....
}
public class Foo{
	public int n = 0;
    private float f = (float)0.0;
    String str = "hello world";
    static int n0 = 0;

    public void Test(){}
    private void Test(int){}
    static void Test(float){}
}

6.2 访问权限控制

关键字 权限
public 共有
private 私有
protected 保护
包权限,包内可以访问

6.3 构造块和静态块

  • 构造块 - 无名的构造,实例化对象的时候调用
  • 静态块 - 当类被解析的时候被调用
  • 时机 - 静态块 >>> 构造块 >>> 构造
class 类名{

    //这是构造块
    {
        //正常代码
    }


    //这是静态块
    static {
        //正常代码
        //只能访问静态成员
    }

}

6.4 包

包是java中库级的代码组织单位,高于类,等同于c++的命名空间。

  • 格式 - package 包名;

    • package语句必须放是文件第一行非注释代码,表明本文件所属的包

    • 包名如果有多个层级,中间使用.隔开,同时是路径名

比如,建立一个包名com.jlw.base

对应的文件夹路径

import

当其它类需要使用指定包中的类时,需要使用import语句

  • 格式1 - import 包名.类名,使用指定包中的指定类
  • 格式2 - import 包名.**是通配符,使用指定包中的所有类
import com.jlw.base.Foo;

public class Main {
    public static void main(String[] args) {
        Foo foo = new Foo();
        //Test test = new Test(); //报错
    }
}
import com.jlw.base.*;

public class Main {
    public static void main(String[] args) {
        Foo foo = new Foo();
        Test test = new Test();
    }
}

7. 继承和多态

7.1 继承

  1. 语法
    • 继承关键字 extends
    • 不允许多继承
public class Base{
	void foo(){
		System.out.println("Base.foo()");
	}
	public int n;
}
public class Derived extends Base{
}
		public static void main(String args){
		Derived d = new Derived();
        d.n = 100;
        d.foo();
    }
  1. 调用父类构造
public class Base{
    Base(){}
    Base(int n){
        this.n = n;
    }
	void foo(){
		System.out.println("Base.foo()");
	}
	public int n;
}
public class Derived extends Base{
    Derived(){}
    Derived(int n){
        // 在带参构造子类时,默认调用父类的无参构造
        // 需要调用父类带参构造
        super(n);
        
        n = 20;
        this.n = 10;
        super.n = 30;
    }
}
  • super可当做父类的类名, 子类通过super关键字访问父类的成员
  • n = 20;修改的是传入参数的值
  • this.n = 10;修改的子类的值
  • super.n = 30;修改的父类的值
  1. instanceof运算符

用于判断某个对象是否是某个类的对象 ( 是否满足该继承体系 )

返回值boolean

b = new Derived2();
boolean bIs = b instanceof Derived2;	// true
bIs = b instanceof Derived;				// false
bIs = b instanceof Base;				// true
  1. 隐藏
  • 子类会隐藏父类同名数据, 如需指定父类数据, 可使用super

7.2 多态

  1. 语法
    • 函数声明相同, 直接在子类重写, 不需要加关键字就可实现多态
public class Derived extends Base{
    void foo(){
        System.out.println("Derived.foo()");
    }
}
	public static void main(String args){
		Derived d = new Derived();
        d.n = 100;
        d.foo();
        
        Base b = new Derived();
        b.foo(); // 调用子类foo函数,自动实现多态
    }

快捷键Ctrl + O快速查看可重写的父类方法, 重写函数上可以添加@Override注解

当子类构造调用到父类构造时, 父类构造调用了子类重新函数foo(); 此时会访问到子类的foo函数, 所以我们不能再父类构造中调用到子类重写的函数

public class Base{
    Base(){}
    Base(int n){
        this.n = n;
        //this.foo(); 	// 子类走父类构造时,调用到了子类重写的foo函数
    }
	void foo(){
		System.out.println("Base.foo()");
	}
	public int n;
}

为了防止父类的部分函数被子类重写, 我们有种方法防止被子类重写

final关键字

public final class Base{	// 类不能被继承
    Base(){}
    Base(int n){
        this.n = n;
        //this.foo(); 	// 子类走父类构造时,调用到了子类重写的foo函数
    }
	final void foo(){	// 函数不能被重写
		System.out.println("Base.foo()");
	}
	public int n;
}

final关键字类似于C++的const, 但是比const的使用范围广, 添加到类前, 则该类不允许被继承, 添加到方法前, 则该方法不允许被重写

7.3 祖宗类

Object

  • java所有的类都继承自Object

    • toString用于输出对象信息

    • equals用于判断对象是否相同

      • 判断类类型需要重写, 否则只能判断基本数据类型和String类型
      public boolean equals(Object obj){
      	Foo foo = (Foo) obj;	// 需要强转为该类类型,祖宗类无法访问Foo类数据成员
      	return n == foo.n;
      }
      
    • clone用于深拷贝

8. 抽象类和接口

8.1 抽象类

java可以定义抽象类, 关键字abstract, 该关键字也可以用于定义抽象方法(C++的纯虚函数)

[访问权限] abstract class 类名{
	[访问权限] abstract 返回值 方法名(参数列表) {
        // 抽象方法
    }
    [访问权限] 数据类型 变量;
}

8.2 接口

java允许定义一种更纯粹的抽象类, 称为接口, class关键字改为interface

  • 定义
    • 接口的成员函数不能有实现
    • 接口不能定义数据成员
    • 接口不能实例化对象
  • 实现
    • java允许接口多重继承
      • public Derived implements Animal
    • 子类必须实现接口的所有成员函数
public interface Animal{
	public void Eat();
	public void Sound();
}

9. 内部类

从代码组织层级来看,类是定义在包级之下。

但java还支持将类定义到更小的组织单位中,比如类中,甚至方法中,统称为内部类。

9.1 内部类

内部类实际上就是一个类内部定义一个外部类的引用, 这个引用必须有一个实例化的对象 ( 用于访问外部类的数据 )

  • 内部类可以定义在其它类内,也可以定义在方法内
  • 内部类可以访问类外作用域的数据和方法,并无视权限
public class Foo {
    private int nFoo = 0;
    private void TestFoo(){
        System.out.println("Foo.Test");
    }

    //定义在类内
    public class Inn{
        public int nInn= 10;
        public void Test(){
            nFoo = 10; //访问外部数据
            TestFoo(); //访问外部方法
            System.out.println("Inn.Test");

            //定义在方法内
            class Inn3{
                public void Test(){
                    nInn = 20; //访问外部数据
                    nFoo = 30; //访问外部数据
                }
            }
        }
    }
}

  • 当出现名称隐藏时,通过类名.this的方式指定作用域
public class Test {
    private int n = 0;
    
    class Inn{
        private int n = 0;
        public void Foo(){
            this.n = 8;      //访问自己的
            Test.this.n = 9; //访问Test的
        }
    }
}
  • 内部类不能独立创建对象,必须使用外部类对象创建
  • 创建时不能直接new,使用对象.new
public class Outer {
    public class Inner{

    }

    public static void main(String[] args) {
        Outer outer = new Outer();
        Outer.Inner inner = outer.new Inner(); //创建内部类对象
    }
}
  • 继承内部类没有意义, 不做讨论

9.2 匿名内部类

  • 格式 - new 类名/接口名 (){}
  • 语义 - 创建一个无名类(继承自指定类,或者实现指定接口)对象
  • 匿名内部类可以定义数据成员
  • 一生只能定义一个对象
public class Outer {

    public interface Inter {
        public void Foo();
    }

    public void Foo(){
        System.out.println("Outer.Foo");
    }

    public static void main(String[] args) {
        //创建匿名类对象
        Outer outer = new Outer(){
            private int n = 0;
            public int n1 = 0;
            public void  Foo(){
                System.out.println("noname.Foo");
            }
        };
        outer.Foo();

        //创建匿名类对象
        Inter inter = new Inter() {
            @Override
            public void Foo() {
                System.out.println("Inter.Foo");
            }
        };
        inter.Foo();
    }
}

9.3 嵌套类

  • 格式 - static class 类名{}
  • 说明 - 内部类使用static修饰
  • 不能访问外部的变量,可以直接创建对象
public class Outer {
    public static class Inner{
        public void Test(){
            System.out.println("Inner.Test");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Outer.Inner inner = new Outer.Inner();
        inner.Test();
    }
}

10. 泛型

10.1 基本语法

  • 类模板格式 - 访问标号 类名<T>{}
  • 函数模板格式 - 访问标号 返回值 函数名<T>{}
    • 意义不大
public class Foo <T>{
    private T val;
    private T Get(){
        return val;
    }
    private void Set(T val){
        this.val = val;
    }

    public static void main(String[] args) {
        Foo<String> foo = new Foo<String>();
        foo.Set("hello");
        System.out.println(foo.Get());
    }
}

10.2 类型擦除

java模板功能比c++的要弱。

在c++中,模板实例化后,模板的类型参数T便成为了具体的类型。

但在java中,模板实例化后,模板的类型参数T便成为了Object

相当于模板内部将实例化模板的类型给擦除了。

package com.kr.testtem;

public class TestErase {
    static public class Foo{
        public void Test(){
            System.out.println("Foo.Test");
        }
    }

    static public class Tem<Foo>{
        public T obj;
        public Tem(T obj){
            this.obj = obj;
        }
        public void Call(){
            obj.Test();  //报错
        }

        public  void Test(){

        }
    }

    public static void main(String[] args) {
        Tem<Foo> tem = new Tem<>(new Foo());
        tem.Call();
    }
}

10.3 边界和通配符

  1. 边界

针对模板内部的类型擦除,java也做出了补偿,允许模板将T视作指定继承家族中的一员,即T都为指定类型的子类,从而在某种程度上调用类型的成员。

这种做法称之为为模板的类型指定边界。

  • 格式 - <T externds 类名>
package com.kr.testtem;

public class TestErase {
    static public class Foo{
        public void Test(){
            System.out.println("Foo.Test");
        }
    }
    static public class CSuperFoo extends Foo{
        public void Test(){
            System.out.println("Foo.Test");
        }
    }

    static public class Tem<T extends Foo>{
        public T obj;
        public Tem(T obj){
            this.obj = obj;
        }
        public void Call(){
            obj.Test();
        }

        public  void Test(){

        }
    }

    public static void main(String[] args) {
        Tem<Foo> tem = new Tem<>(new CSuperFoo());
        tem.Call();
    }
}
  1. 通配符

10.4 容器

11. 异常

  • 抛出异常 - throw new 异常

  • 接收异常 - try{}catch(异常){}

  • finally 块 - 跟在在try后,无论是否有异常,都会执行finally

  • 所有异常的父类都是Exception

  • throws说明

    • 所有方法,如果有未处理的异常,均要说明

    • 格式 - 方法 throws 异常1,异常2 。。。

package com.kr.testexp;

import com.kr.testtem.TestErase;

public class Test {
    //自定义异常
    static public class MyException extends Exception{
        public MyException(String str){
            super(str);
        }
    }

    //自定义异常
    static public class MyException2 extends Exception{
        public MyException2(String str2){
            super(str2);
        }
    }

    //方法异常签名
    public void Foo(int n) throws MyException, MyException2 {
        if (n>0){
            throw new MyException("test"); //抛出异常
        }else {
            throw  new MyException2("2");//抛出异常
        }

    }

    public static void main(String[] args) {
        Test t = new Test();

        //接收异常
        try {
            t.Foo(1);
        } catch (MyException e) {
            System.out.println(e.getMessage());
            e.printStackTrace();
        } catch (MyException2 e) {
            e.printStackTrace();
        } finally {
            System.out.println("finally");
        }
    }
}

11.1 try…catch

public class Main(){
	public static void main(String[] args){
		try{
			throw new Exception("异常");
		}catch (Exception e){
			//System.out.println(e.toString());
            e.printStackTrace();
		}
	}
}

11.2 往外抛

throw Exception

	public class Foo{
		public void foo() throw Exception {
        	throw new Exception("异常");
    	}
    }
public class Main(){
	public static void main(String[] args) throw Exception{
        Foo foo = new Foo();
        foo.foo();
	}
}

12. 常用库类

  • 字符串类 String
    • java中所有的字符串都是String类对象
    • 文本块"""\n""", 中间可以跨行,
      • \用于换行拼接
  • 计算Math
  • 数组Array
posted @ 2024-03-22 21:36  丨M0nster  阅读(20)  评论(0)    收藏  举报