Java学习

这是笔者学习 Java 时记录的一些内容。不能算笔记,记录的内容杂且乱。

学习Java 主要参考的是菜鸟教程和 Java 官方文档 Overview (Java Platform SE 8 ) (oracle.com)

JDK 21的文档读起来太难受了,因此读 JDK 8。菜鸟教程上有 JDK 11的中文文档,也可拿来参考。

语言基础

Java 是纯粹的面向对象的程序设计语言,语言非常简单。

Java 程序在 Java 平台上被编译为体系结构中立的字节码格式(后缀为 class 的文件),然后可以在实现这个 Java 平台的任何系统中运行。在运行时,Java 平台中的 Java 解释器对这些字节码进行解释执行,执行过程中需要的类在联接阶段被载入到运行环境中。

所有方法名应以小写字母开头。源文件名必须和类名相同

运行:假设类名为 HelloWorld,那么保存的文件应为 HelloWorld.java,cmd 中编译 java 代码的指令是 javac HelloWorld.java,将 java 源代码编程成字节码文件 class,再用指令 java HelloWorld 执行字节码文件。

javac和java命令详解教程 - 知乎 (zhihu.com)

源文件声明规则

当在一个源文件中定义多个类,并且还有 import 语句和 package 语句时,要特别注意这些规则。

  • 一个源文件中只能有一个 public 类
  • 一个源文件可以有多个非 public 类
  • 源文件的名称应该和 public 类的类名保持一致。例如:源文件中 public 类的类名是 A,那么源文件应该命名为 A.java。实际工程中不要用这么糟糕的类名。
  • 如果一个类定义在某个包中,那么 package 语句应该在源文件的首行。
  • 如果源文件包含 import 语句,那么应该放在 package 语句和类定义之间。如果没有 package 语句,那么 import 语句应该在源文件中最前面。
  • import 语句和 package 语句对源文件中定义的所有类都有效。在同一源文件中,不能给不同的类不同的包声明。

import 语句:提供路径,使得编译器可以找到某个类。

数据类型

float 是单精度、32 位;double 是双精度、64 位;小数默认是 double 类型浮点型

boolean 取 true 或 false。

常量关键字:final

string与int转换:

变量类型

  • 局部变量(Local Variables):定义在方法、构造方法或语句块中的变量,作用域只限于当前方法、构造方法或语句块中。局部变量必须在使用前声明,并且不能被访问修饰符修饰。
  • 成员变量(Instance Variables):定义在类中、方法之外的变量,作用域为整个类,可以被类中的任何方法、构造方法和语句块访问。成员变量可以被访问修饰符修饰。
  • 静态变量(Class Variables):定义在类中、方法之外的变量,并且使用 static 关键字修饰,作用域为整个类,可以被类中的任何方法、构造方法和语句块访问,静态变量的值在程序运行期间只有一个副本。静态变量可以被访问修饰符修饰。
  • 参数变量(Parameters):方法定义时声明的变量,作为调用该方法时传递给方法的值。参数变量的作用域只限于方法内部。

参数变量的值传递方式有两种:值传递引用传递

值传递传递的是实际参数的值的副本。当参数变量被赋予新的值时,只会修改副本的值,不会影响原始值。Java 中的基本数据类型都采用值传递方式传递参数变量的值。

引用传递传递的是实际参数的引用(即内存地址)。当参数变量被赋予新的值时,会修改原始值的内容。Java 中的对象类型采用引用传递方式传递参数变量的值。

常量和静态变量的区别

常量是用 final 关键字修饰,一旦被赋值就不能再修改。

常量在编译时就已经确定了它的值,而静态变量的值可以在运行时改变。

静态变量是与类相关的变量,具有唯一性和共享性,可用于存储整个程序都需要使用的数据。

静态变量的线程安全性

Java 中的静态变量是属于类的,而不是对象的实例。当多个线程同时访问一个包含静态变量的类时,需要考虑其线程安全性。

静态变量在内存中只有一份拷贝,被所有实例共享。因此,如果一个线程修改了静态变量的值,那么其他线程在访问该静态变量时也会看到修改后的值。这可能会导致并发访问的问题,因为多个线程可能同时修改静态变量,导致数据一致性问题。

为了确保静态变量的线程安全性,需要采取适当的同步措施,如同步机制、原子类或 volatile 关键字,以便在多线程环境中正确地读取和修改静态变量的值。

访问修饰符:

使用访问控制符来保护对类、变量、方法和构造方法的访问

  • default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
  • private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
  • public : 对所有类可见。使用对象:类、接口、变量、方法
  • protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)

访问控制和继承

  • 父类中声明为 public 的方法在子类中也必须为 public。
  • 父类中声明为 protected 的方法在子类中要么声明为 protected,要么声明为 public,不能声明为 private。
  • 父类中声明为 private 的方法,不能够被子类继承。

其它修饰符:

​ static : 独立于对象的静态变量,无论一个类实例化多少对象,它的静态变量只有一份拷贝。

​ final : 常量,不能被继承。

​ abstract : 抽象类,不能用来实例化对象,声明其的唯一目的是为了将来对该类进行扩充。

​ synchronized : 声明的方法同一时间只能被一个线程访问。

volatile : 修饰的成员变量每次被线程访问时,强制从共享内存中重新读取该成员变量的值。且当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。

循环:

与 C/C++ 基本相同。不过多了主要用于数组的增强型 for 循环。

1
2
3
for(int x : numbers ){
System.out.print( x );
}

String

string修改的话用 StringBuilder 和 StringBuffer 这两个类,StringBuilder 速度更快,但 StringBuffer 可以保证线程安全。

数组

Java 中数组一般这样:

1
int[] mylist = new mylist()

方法:

类比 C/C++ 中的函数。

构造方法:

老东西了,但还是复习一下吧,当初面向对象学得依托答辩,本来就没学多好

对象被创建时候,构造方法用来初始化该对象。构造方法和所在类的名字相同。

所有的类都有构造方法

输入输出:

读写数据:

1
Scanner in = new Scanner(System.in);//接受来自键盘的输入

然后需要读输入的数据时:

1
2
int a = in.nextLine();//nextLine以Enter为结束符,返回的是输入回车之前的所有字符
//in.next() 遇到空格就会停止接收。

文件读写:

实质是文件夹。定义包的格式:package xxx;

面向对象相关:

引用类型的默认值是null。

一个源文件中只能有一个 public 类,可以有多个非 public 类

源文件的名称应该和 public 类的类名保持一致。如源文件中 public 类的类名是 A,那么源文件应该命名为 A.java。实际工程中不要用这么糟糕的类名。

封装

将抽象性函式接口的实现细节部分包装、隐藏起来的方法。

封装可以防止该类的代码和数据被外部类定义的代码任意访问。要访问该类的代码和数据,必须通过严格的接口控制

private

权限修饰符 private 可以修饰成员变量与成员方法,被 private 修饰的成员只能在本类中访问。

private 用于私有化成员变量,同时需要对外提供 getXsetx 方法。

构造方法:

构造方法是创建类后用于给成员变量

包括无参构造方法与有参构造方法。无参构造方法是创建类后就会自动有的,但是无论何时都建议自己写无参构造方法。

封装实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
class Employee {
private String eid;
private String name;
private String job;

public Employee() {}
public Employee(String eid,String name,String job) {
this.eid = eid;
this.name = name;
this.job = job;
}

public void setEid(String eid) {
this.eid = eid;
}
public String getEid() {
return eid;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setJob(String job) {
this.job = job;
}
public String getJob() {
return job;
}
}

现在访问这些变量只能通过这些方法访问,而不能直接查看。

继承

Java 不支持多继承,但 Java 支持多层继承

继承原则:子类只能继承父类所有非 private 的成员(方法和变量)

子类不能继承父类的构造方法,但是可以通过 super 关键字去访问父类构造方法。

子类中所有的构造方法默认都会访问父类中空参数的构造方法,因为子类会继承、使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。因此,子类每一个构造方法的第一条语句默认都是:super()

如果想直接使用成员变量,使用 this 关键字;如果想直接使用父类的成员变量,使用 super 关键字。

如果父类构造器没有参数,则在子类的构造器中系统会自动调用父类的无参构造器。先调用父类再调用子类。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class A{
A(){
System.out.println("A");
}
}
class B extends A{
B(){//会自动调用父类 A 的无参数构造器。
System.out.println("B");
}
}
public class tmp{
public static void main(String[] args){
B b1 = new B();
}
}

最终输出是A B。先调用了父类 A 的无参数构造器再调用了子类的B 的。

重写:

子类中出现了和父类中一模一样的方法声明,即子类重写了父类的方法。

子类重写父类的方法:

  • 不能重写父类私有方法
  • 子类重写父类方法的权限建议与父类相同
  • 父类方法静态,子类也应静态

单继承关键字:extends class Dog extends Animal

多继承关键字:implement public class C implements A,B

匿名对象:

仅仅被使用一次的时候适用,作为实际参数传递

如:new.Student().love();

this

成员变量在堆,局部变量在栈。

this:代表本类的对象。用于区分成员变量与局部变量。

应用场景: 局部变量隐藏成员变量

static

static 是静态关键字,表示成员变量是被共享的。

static 所修饰的变量或方法 随着类的加载而加载、优先于对象存在、被类的所有对象共享

静态的内容是被所有对象共享的,非静态的是每个对象特有的

非静态的成员方法可以访问静态与非静态的成员变量、方法;静态的成员方法只能访问静态的成员变量、方法。

final

final 修饰类后,此类便无法被继承;final 修饰变量后,就变成了常量。值不能被修改;final 修饰方法后,此方法就不能被子类重写。

多态

多态,即同一个对象在不同时刻表现出现的不同状态。

关于多态:

  • 成员变量与静态方法: 编译看左边,运行看左边。

  • 成员方法:编译看左边,运行看右边。

抽象类

不是所有的类都是用来描绘对象的。如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。

Java 抽象类关键字:abstract

类中的方法如果是抽象的,那么该类就必须定义为抽象类

  • 抽象类和抽象方法必须用abstract关键字修饰
  • 抽象类的子类要么是抽象类、要么重写抽象类中的所有抽象方法
  • 抽象类不一定有抽象方法,但有抽象方法的类一定是抽象类
  • 抽象类以及抽象类中的构造方法不能被实例化

不能与 abstract 共用的关键字:private、final、static

构建抽象类 A 后,我们不能实例化抽象类 A 的对象,但我们可以构建类 B 继承抽象类 A ,然后实例化 B 的对象。

接口

“对功能的扩展”,一个抽象类型,包含类要实现的方法。

接口用关键字 interface 表示,interface 接口名 {}

类实现接口用 implements 表示

接口不支持实例化,支持的是多态。

接口的成员变量是 public static final 的,没有构造方法,成员方法只能是 public abstract 的。

接口不是被类继承了,而是要被类实现。接口支持多继承。

类与类之间是继承关系,只能单继承。可以多层继承。

类与接口之间是实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口。

接口与接口之间是继承关系,可以单继承,也可以多继承。

一些特性:

  • 接口中的方法会被隐式的指定为 public abstract,变量会被隐式的指定为 public static final 变量
  • 接口中的方法是不能在接口中实现的,只能由实现接口的类来实现接口中的方法。

内部类

把类定义在其他类的内部。内部类可以直接访问外部类的成员,包括私有。

内部类可以直接访问外部类的任何成员,包括私有。外部类要访问内部类的成员,必须创建对象。

为了不让外界直接访问内部对象,内部类一般用 private 修饰。

数据结构

vector

向量,动态数组。使用如下所示:

与下面的 ArrayList 相比,Vector 是线程安全的。

ArrayList

ArrayList 类也是一个可以动态修改的数组,用法上与 Vector几乎相同。速度比 Vector 更快,但不是同步的。

LinkedList

链表,增加和删除的操作效率更高,查找修改的操作效率更低。

HashMap

一个散列表,存储的内容是键值对 (key-value) 映射,无序的。

迭代器 Iterator

一种用于遍历的接口。提供了统一的方式来访问元素而无需知道底层细节。

  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.

扫一扫,分享到微信

微信分享二维码

请我喝杯咖啡吧~

支付宝
微信