【廖雪峰Java】Java基础知识

本文详细介绍了Java语言的基础知识,包括Java之父、不同版本的对比、JDK与JRE、基本操作(如命名规范、数据类型、运算、数组、输入输出等)、面向对象编程(构造方法、方法重载、继承、多态、抽象类、接口、静态成员)以及内部类等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

学习课程:廖雪峰的官方网站:https://www.liaoxuefeng.com/

1、简介

1.1、Java之父

詹姆斯·高斯林(James Gosling)

1.2、Java三个不同版本

  • Java SE:Standard Edition
  • Java EE:Enterprise Edition
  • Java ME:Micro Edition

这三者之间有啥关系呢?
在这里插入图片描述

1.3、JDK 与 JRE

  • JDK:Java Development Kit
  • JRE:Java Runtime Environment

在这里插入图片描述

1.4、如何运行Java程序

Java源码本质上是一个文本文件,我们需要先用javac把Hello.java编译成字节码文件Hello.class,然后,用java命令执行这个字节码文件:
在这里插入图片描述


2、基本操作

2.1、命名规范

  • 包命名:com.hello.world

  • 类、接口命名:HelloWorld

  • 方法命名:helloWorldHelloWorld

  • 变量命名:helloWorldHelloWorld

  • 常量命名:HELLO_WORLD

2.2、基本数据类型

  • 整数类型:byte,short,int,long
  • 浮点数类型:float,double
  • 字符类型:char
  • 布尔类型:boolean

Java基本数据类型占用的字节数:
在这里插入图片描述

特别注意:同一个数的不同进制的表示是完全相同的,例如15=0xf=0b1111。

2.3、浮点型定义

对于float类型,需要加上f后缀。

float f1 = 3.14f;
float f2 = 3.14e38f; // 科学计数法表示的3.14x10^38
float f3 = 1.0; // 错误:不带f结尾的是double类型,不能赋值给float

double d = 1.79e308;

2.4、字符

char a = 'A';

2.5、引用

引用类型最常用的就是String字符串:

String s = "hello";

C++中引用和指针的区别:https://blog.csdn.net/smartgps2008/article/details/90648015

2.6、常量

定义变量的时候,如果加上final修饰符,这个变量就变成了常量:

final double PI = 3.14; // PI是一个常量

2.7、var关键字

有些时候,类型的名字太长,写起来比较麻烦。如果想省略变量类型,可以使用var关键字,以下两者等效。

StringBuilder sb = new StringBuilder();
var sb = new StringBuilder();

2.8、运算优先级

在Java的计算表达式中,运算优先级从高到低依次是:
()
! ~ ++ –
* / %
+ -
<< >> >>>
&
|
+= -= *= /=

2.9、浮点数运算

  • 浮点数常常无法精确表示,并且浮点数的运算结果可能有误差;
  • 比较两个浮点数通常比较它们的差的绝对值是否小于一个特定值;
  • 整型和浮点型运算时,整型会自动提升为浮点型;
  • 可以将浮点型强制转为整型,但超出范围后将始终返回整型的最大值。

举个栗子:
浮点数0.1在计算机中就无法精确表示,因为十进制的0.1换算成二进制是一个无限循环小数,很显然,无论使用float还是double,都只能存储一个0.1的近似值。

double x = 1.0 / 10;
double y = 1 - 9.0 / 10;
// 观察x和y是否相等:
System.out.println(x); // x=0.1
System.out.println(y); // y=0.09999999999999998

所以要特别注意浮点数的运算,判断浮点数相等用“==”判断不靠谱,正确的方法是利用差值小于某个临界值来判断。比如:

double x = 1 - 9.0 / 10;  // x=0.09999999999999998
// 不要使用==直接判断,错误写法:if (x == 0.1) {}
// 而是使用差值小于某个临界值来判断
if (Math.abs(x - 0.1) < 0.00001) {}

2.10、char 和 String 的区别

\charString
定义字符字符串
类型基本类型引用类型
描述“持有”某个数值“指向”某个对象
符号使用‘’“”

2.11、Java中数组的特点

  • 数组所有元素初始化为默认值,整型都是0,浮点型是0.0,布尔型是false;
  • 数组一旦创建后,大小就不可改变;
  • 数组元素可以是值类型(如int)或引用类型(如String),但数组本身是引用类型。

可以用数组变量.length获取数组大小:

int[] ns = new int[] { 68, 79, 91, 85, 62 };
System.out.println(ns.length); // 编译器自动推算数组大小为5

2.12、input & output

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in); // 创建Scanner对象
        System.out.print("Input your name: "); // 不换行输出
        String name = scanner.nextLine(); // 读取一行输入并获取字符串
        System.out.println("Input your age: "); // 换行输出
        int age = scanner.nextInt(); // 读取一行输入并获取整数
        System.out.printf("Hi, %s, you are %d\n", name, age); // 格式化输出
    }
}

2.13、== 和 equals() 的区别

  • == :表示“引用是否相等”
  • equals() :判断引用类型的变量内容是否相等
String s1 = "hello";
String s2 = "HELLO".toLowerCase();
System.out.print(s1 == s2); // false
System.out.print(s1.equals(s2)); // true

2.14、switch

使用switch要留意需不需要使用break,注意千万不要漏写break。

2.15、for each循环

int[] ns = { 1, 4, 9, 16, 25 };
// 使用for循环
for (int i=0; i<ns.length; i++) {
    System.out.println(ns[i]);
}
// 使用for each循环
for (int n : ns) {
	System.out.println(n);
}

2.16、break & continue

  • break : 语句可以跳出当前循环;
  • continue : 语句可以提前结束本次循环;

2.17、数组操作

  • 遍历数组可以使用for循环,for循环可以访问数组索引,for each循环直接迭代每个数组元素,但无法获取索引;
  • 使用Arrays.toString()可以快速获取数组内容;
  • 可以直接使用Java标准库提供的Arrays.sort()进行排序;
  • 打印多维数组可以使用Arrays.deepToString();
int[] ns = { 28, 12, 89, 73, 65, 18, 96, 50, 8, 36 };
// 遍历:方法一
for (int i=0; i<ns.length; i++) {
	int n = ns[i];
	System.out.println(n);
}
// 遍历:方法二
for (int n : ns) {
    System.out.println(n);
}
//直接打印,不能得到想要的结果
System.out.println(ns); // 直接打印数组变量,得到的是数组在JVM中的引用地址。类似 [I@7852e922
// 调用Java标准库
import java.util.Arrays;
System.out.println(Arrays.toString(ns));
// 其他方法
Arrays.sort(ns);

3、面向对象(OOP)

3.1、构造方法

  • 实例在创建时通过new操作符会调用其对应的构造方法,构造方法用于初始化实例;
  • 没有定义构造方法时,编译器会自动创建一个默认的无参数构造方法;(要特别注意的是,如果我们自定义了一个构造方法,那么,编译器就不再自动创建默认构造方法。)
  • 可以定义多个构造方法,编译器根据参数自动判断;
  • 可以在一个构造方法内部调用另一个构造方法,便于代码复用。
// 构造方法用于初始化实例
Person p = new Person("Xiao Ming", 15);
Person p2 = new Person("Xiao Ming"); // 自动匹配到构造方法

class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person(int age) {
        this.name = "xiaoming";
        this.age = age;
    }
    
    public Person(String name) {
        this(name, 18); // 调用另一个构造方法Person(String, int)
    }
}

3.2、方法重载

  • 方法重载是指多个方法的方法名相同,但各自的参数不同;
  • 重载方法应该完成类似的功能;
  • 重载方法返回值类型应该相同。
class Hello {
    public void hello() {
        System.out.println("Hello, world!");
    }

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

3.3、继承

Java使用extends关键字来实现继承:

class Person {
    private String name;
    private int age;
    ...
    public String getName() {...}
    public void setName(String name) {...}
    ...
}

class Student extends Person {
    // 不要重复定义name和age字段/方法,
    private int score; // 在父类基础之上新增字段和方法
    ...
    public int getScore() {}
    public void setScore(int score) {}
}

子类自动获得了父类的所有字段,严禁定义与父类重名的字段!
在父类与子类之间,方法名,参数列表,返回类型都相同,是被允许的。这种现象称为方法的重写。

在OOP的术语中,我们把Person称为超类(super class),父类(parent class),基类(base class),把Student称为子类(subclass),扩展类(extended class)。

继承树:

在这里插入图片描述

  • super关键字表示父类(超类)。子类引用父类的字段时,可以用super.fieldName。
  • this关键字表示本身调用的类。一般用法this.fieldName。

如果父类没有默认的构造方法,子类就必须显式调用super()并给出参数以便让编译器定位到父类的一个合适的构造方法。(栗子)

小结:

  • 继承是面向对象编程的一种强大的代码复用方式;(减小代码冗余)
  • Java只允许单继承,所有类最终的根类是Object;(C++允许多继承方式)
  • protected允许子类访问父类的字段和方法;
  • 子类的构造方法可以通过super()调用父类的构造方法;
  • 可以安全地向上转型为更抽象的类型;
  • 可以强制向下转型,最好借助instanceof判断;
  • 子类和父类的关系是is,has关系不能用继承。
  • 在Java中,没有明确写extends的类,编译器会自动加上extends Object。所以,任何类,除了Object,都会继承自某个类。
  • Java只允许一个class继承自一个类,因此,一个类有且仅有一个父类。只有Object特殊,它没有父类。但是,Java允许一个class被多个类继承。

3.4、多态

Override
子类对父类方法进行重写时,方法类型、方法名、方法参数必须都相同相同

class Person {
    public void run() {
        System.out.println("Person.run");
    }
}

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}
  • 子类可以覆写父类的方法(Override),覆写在子类中改变了父类方法的行为;
  • Java的方法调用总是作用于运行期对象的实际类型,这种行为称为多态;
  • final修饰符有多种作用:
    • final修饰的方法可以阻止被覆写;
    • final修饰的class可以阻止被继承;
    • final修饰的field必须在创建对象时初始化,随后不可修改。

3.5、抽象类

  • 通过abstract定义的方法是抽象方法,它只有定义,没有实现。抽象方法定义了子类必须实现的接口规范;
  • 定义了抽象方法的class必须被定义为抽象类,从抽象类继承的子类必须实现抽象方法;
  • 如果不实现抽象方法,则该子类仍是一个抽象类;
  • 面向抽象编程使得调用者只关心抽象方法的定义,不关心子类的具体实现。

3.6、接口

  • Java的接口(interface)定义了纯抽象规范,一个类可以实现多个接口;
  • 接口也是数据类型,适用于向上转型和向下转型;
  • 接口的所有方法都是抽象方法,接口不能定义实例字段;
  • 接口可以定义 default 方法(JDK>=1.8)。

抽象类和接口的对比如下:

\abstract classinterface
继承只能extends一个class可以implements多个interface
字段可以定义实例字段不能定义实例字段
抽象方法可以定义抽象方法可以定义抽象方法
非抽象方法可以定义非抽象方法可以定义default方法

3.8 静态字段与静态方法

实例字段在每个实例中都有自己的一个独立“空间”,但是静态字段只有一个共享“空间”,所有实例都会共享该字段。
调用实例方法必须通过一个实例变量,而调用静态方法则不需要实例变量,通过类名就可以调用。

public class Main {
    public static void main(String[] args) {
        Person.setNumber(99);
    }
}

class Person {
    public String name;
    public int age;
    // 定义静态字段number:
    public static int number;
    // 静态方法
    public static void setAge(int value) {
        this.age = value;
    }
}

如下两实例对象:
在这里插入图片描述

3.8 内部类(Nested Class)

class Outer {
    class Inner {
        // 定义了一个Inner Class
    }
}
廖雪峰 Java 教程 Java教程 Java快速入门 Java简介 安装JDK 第一个Java程序 Java代码助手 使用IDE 使用IDE练习插件 Java程序基础 Java程序基本结构 变量和数据类型 整数运算 浮点数运算 布尔运算 字符和字符串 数组类型 流程控制 输入和输出 if判断 switch多重选择 while循环 do while循环 for循环 break和continue 数组操作 遍历数组 数组排序 多维数组 命令行参数 面向对象编程 面向对象基础 方法 构造方法 方法重载 继承 多态 抽象类 接口 静态字段和静态方法 包 作用域 classpath和jar 模块 Java核心类 字符串和编码 StringBuilder StringJoiner 包装类型 JavaBean 枚举类 BigInteger BigDecimal 常用工具类 异常处理 Java的异常 捕获异常 抛出异常 自定义异常 使用断言 使用JDK Logging 使用Commons Logging 使用Log4j 使用SLF4J和Logback 反射 Class类 访问字段 调用方法 调用构造方法 获取继承关系 动态代理 注解 使用注解 定义注解 处理注解 泛型 什么是泛型 使用泛型 编写泛型 擦拭法 extends通配符 super通配符 泛型和反射 集合 Java集合简介 使用List 编写equals方法 使用Map 编写equals和hashCode 使用EnumMap 使用TreeMap 使用Properties 使用Set 使用Queue 使用PriorityQueue 使用Deque 使用Stack 使用Iterator 使用Collections IO File对象 InputStream OutputStream Filter模式 操作Zip 读取classpath资源 序列化 Reader Writer PrintStream和PrintWriter 日期与时间 基本概念 Date和Calendar LocalDateTime ZonedDateTime DateTimeFormatter Instant 最佳实践 单元测试 编写JUnit测试 使用Fixture 异常测试 条件测试 参数化测试
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值