生活所迫呀。
由于生活所迫,我宣布我现在开始学java。
第 1 章:类与对象实战
1.1 定义类、属性、方法
在 Java 中,类(class)是对象的模板,对象(object)是类的实例。类中可以包含:
- 属性(字段、变量):描述对象的特征
- 方法:描述对象的行为
如:
1 2 3 4 5 6 7 8 9 10
| public class Person{ String name; int age;
void sayHello(){ System.out.println(name); } }
|
1.2 创建对象并调用方法
创建对象用关键字 new
。创建后可以访问属性或调用方法。
如:
1 2 3 4 5 6 7 8
| public class Main{ public static void main(String[] args) { Person p = new Person(); p.name = "fty"; p.age = 23; p.sayHellow(); } }
|
1.3 构造方法编写与重载
构造方法(Constructor) 是在 new
一个对象时调用的方法,用来初始化属性。
- 构造方法名必须与类名相同
- 构造方法可以有多个(重载)
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| public class Person{ String name; int age;
public Person() { name = "Unknown"; age = 0; }
public Person(String name, int age) { this.name = name; this.age = age; } }
|
1.4 使用 this
关键字
this
是 Java 中的一个关键字,代表“当前对象”。
用在两个场景中:
- 解决方法参数名和属性名冲突
- 在类的方法中调用该对象自己的属性或方法
如:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Person{ String name; int age;
public Person(String name, int age) { this.name = name; this.age = age; }
void showInfo() { System.out.println(this.name + this.age); } }
|
第 2 章:封装与访问控制实践
2.1 使用 private
属性封装数据
在 Java 中,封装(Encapsulation) 是把对象的属性隐藏起来,只通过方法进行访问和修改。
这通常通过把属性设为 private
实现,防止外部直接访问。
如:
1 2 3 4 5 6 7 8
| public class Person { private String name; private int age;
void introduce() { System.out.println("Hi, my name is " + name + ", I’m " + age + " years old."); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Person p = new Person(); } }
|
2.2 编写 Getter / Setter
Getter/Setter 是访问私有属性的“通道”:
getXxx()
获取属性值
setXxx()
设置属性值
如:
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
| public class Person { private String name; private int age;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { if (age >= 0 && age <= 150) { this.age = age; } else { System.out.println("Invalid age."); } } }
|
1 2 3 4 5 6 7 8 9
| public class Main { public static void main(String[] args) { Person p = new Person(); p.setName("Alice"); p.setAge(20); System.out.println("Name: " + p.getName()); System.out.println("Age: " + p.getAge()); } }
|
2.3 类的访问控制修饰符应用
Java 提供四种访问修饰符控制类和类成员的访问范围:
修饰符 |
类内 |
同包 |
子类 |
其他包 |
private |
✅ |
❌ |
❌ |
❌ |
default (无修饰) |
✅ |
✅ |
❌ |
❌ |
protected |
✅ |
✅ |
✅ |
❌ |
public |
✅ |
✅ |
✅ |
✅ |
如: |
|
|
|
|
1 2 3 4 5 6 7 8 9 10
| public class Animal { public String type = "Mammal"; protected String sound = "Growl"; String color = "Brown"; private int age = 3;
public void show() { System.out.println("Animal info: " + type + ", " + sound + ", " + color + ", " + age); } }
|
1 2 3 4 5 6 7 8 9
| public class Main { public static void main(String[] args) { Animal a = new Animal(); System.out.println(a.type); System.out.println(a.sound); System.out.println(a.color); } }
|
第 3 章:继承语法与调用关系
3.1 使用 extends
实现继承
ava 使用 extends
关键字让一个类继承另一个类的属性和方法。
✅ 继承的作用:
- 子类拥有父类的非 private 成员(属性和方法)
- 避免重复代码
- 体现「是一种(is-a)」的关系
如:
1 2 3 4 5
| public class Animal { public void eat() { System.out.println("Animal is eating..."); } }
|
1 2 3 4 5
| public class Dog extends Animal { public void bark() { System.out.println("Dog is barking..."); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Dog dog = new Dog(); dog.eat(); dog.bark(); } }
|
3.2 子类调用父类构造器与方法
- 构造器不能继承,但可以通过
super()
调用父类构造器。
- 子类实例化时,默认会先调用父类的无参构造器。
如:
3.2.1 父类有无参构造
1 2 3 4 5 6 7 8 9 10
| public class Animal { public Animal() { System.out.println("Animal constructor called"); } } public class Dog extends Animal { public Dog() { System.out.println("Dog constructor called"); } }
|
3.2.2 父类只有有参构造时,子类必须显式调用
1 2 3 4 5 6 7 8 9 10 11
| public class Animal { public Animal(String name) { System.out.println("Animal: " + name); } } public class Dog extends Animal { public Dog() { super("Buddy"); System.out.println("Dog created"); } }
|
3.3 使用 super
调用父类成员
super.变量名
:访问父类的属性
super.方法名()
:调用父类的方法
通常在子类重写父类方法时,用 super
调用原始实现。
1 2 3 4 5 6 7 8 9 10 11
| public class Animal { public void move() { System.out.println("Animal moves"); } } public class Bird extends Animal { public void move() { super.move(); System.out.println("Bird flies"); } }
|
3.4 子类方法重写(@Override
)
当子类对父类已有方法进行重新实现,称为“方法重写”或“覆盖”。
必须:
- 方法名、参数列表相同
- 使用
@Override
注解(推荐)
如:
1 2 3 4 5 6 7 8 9 10 11
| public class Animal { public void sound() { System.out.println("Animal makes a sound"); } } public class Cat extends Animal { @Override public void sound() { System.out.println("Cat meows"); } }
|
1 2 3 4 5 6
| public class Main { public static void main(String[] args) { Animal a = new Cat(); a.sound(); } }
|
虽然类型是 Animal
,但调用的是 Cat
的实现 —— 这就是多态的表现。
第 4 章:方法重载与重写
4.1 方法重载实现
方法重载是指在同一个类中,方法名相同,但参数列表不同(个数或类型)。其特点为:
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Calculator { public int add(int a, int b) { return a + b; }
public double add(double a, double b) { return a + b; }
public int add(int a, int b, int c) { return a + b + c; } }
|
1 2 3 4 5 6 7 8
| public class Main { public static void main(String[] args) { Calculator c = new Calculator(); System.out.println(c.add(1, 2)); System.out.println(c.add(1.5, 2.5)); System.out.println(c.add(1, 2, 3)); } }
|
4.2 方法重写规则
方法重写发生在继承结构中,子类重写父类已有方法,必须满足以下规则:
要求 |
内容 |
方法名 |
必须相同 |
参数列表 |
必须相同 |
返回值类型 |
必须相同或子类型 |
访问权限 |
不能低于父类 |
抛出异常 |
不能抛出更多的受检异常 |
标记 |
建议使用 @Override 注解 |
如: |
|
1 2 3 4 5 6 7 8 9 10 11 12
| class Animal { public void makeSound() { System.out.println("Animal sound"); } }
class Dog extends Animal { @Override public void makeSound() { System.out.println("Dog barks"); } }
|
1 2 3 4 5 6
| public class Main { public static void main(String[] args) { Animal a = new Dog(); a.makeSound(); } }
|
4.3 重写 vs 重载对比实战
特性 |
重载(Overload) |
重写(Override) |
定义位置 |
同一个类中 |
子类与父类之间 |
方法名 |
相同 |
相同 |
参数列表 |
必须不同 |
必须相同 |
返回值 |
可不同(不构成重载) |
必须相同或是子类类型 |
访问修饰符 |
无限制 |
子类不能比父类更严格 |
多态 |
编译时多态 |
运行时多态 |
第 5 章:多态与父类引用
5.1 父类引用指向子类对象
在Java中,父类类型的引用变量可以指向子类对象。这称为“向上转型”(Upcasting),是多态的基础。
如上面提到的:
- 这里
a
的类型是Animal
,但实际引用的是Dog
对象。
- 父类引用只能访问父类中声明的成员(变量和方法)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| class Animal { public void makeSound() { System.out.println("Animal sound"); } }
class Dog extends Animal { public void makeSound() { System.out.println("Dog barks"); }
public void wagTail() { System.out.println("Dog wags tail"); } }
public class Main { public static void main(String[] args) { Animal a = new Dog(); a.makeSound(); } }
|
5.2 多态方法调用效果
虽然引用类型是父类,但方法调用执行的是子类重写后的版本,体现“运行时绑定”。这让程序更加灵活,接口统一,具体实现多样。
- 调用方法时,会执行子类重写的方法(如果有);
- 访问成员变量时,访问的是引用类型所属类的变量(不支持多态);
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| class Animal { public String name = "Animal";
public void printName() { System.out.println(name); } }
class Cat extends Animal { public String name = "Cat";
@Override public void printName() { System.out.println(name); } }
public class Main { public static void main(String[] args) { Animal a = new Cat(); System.out.println(a.name); a.printName(); } }
|
5.3 多态与数组、集合应用
多态也可以与数组和集合结合使用,方便统一管理不同子类对象。
如:
5.3.1 多态数组
1 2 3 4 5 6 7 8
| Animal[] animals = new Animal[3]; animals[0] = new Dog(); animals[1] = new Cat(); animals[2] = new Animal();
for (Animal a : animals) { a.makeSound(); }
|
5.3.2 多态集合
1 2 3 4 5 6 7 8 9 10
| import java.util.ArrayList; import java.util.List;
List<Animal> animalList = new ArrayList<>(); animalList.add(new Dog()); animalList.add(new Cat());
for (Animal a : animalList) { a.makeSound(); }
|
第 6 章:Object
类与常用方法
6.1 toString()
方法重写
toString()
是 Object
类中定义的方法,所有Java类默认继承。 默认实现返回的是对象的类名 + @ + 哈希码,不够直观。 重写 toString()
让对象打印时更具可读性,常用于调试和日志。
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| public class Person { private String name; private int age;
public Person(String name, int age) { this.name = name; this.age = age; }
@Override public String toString() { return "Person{name='" + name + "', age=" + age + "}"; } }
public class Main { public static void main(String[] args) { Person p = new Person("Alice", 25); System.out.println(p); } }
|
6.2 equals()
比较对象内容
默认 equals()
方法是比较两个对象的引用地址(即是否是同一个对象), 重写 equals()
方法,通常基于对象的属性内容进行比较。常与 hashCode()
一起重写,以保证集合中的正确行为。
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public class Person { private String name; private int age;
@Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false;
Person other = (Person) obj; return age == other.age && (name != null ? name.equals(other.name) : other.name == null); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Person p1 = new Person("Bob", 30); Person p2 = new Person("Bob", 30); System.out.println(p1.equals(p2)); } }
|
6.3 clone()
方法与浅拷贝
clone()
是 Object
中的一个方法,用来复制对象。 默认实现是浅拷贝:基本类型拷贝,引用类型只复制引用。 需要实现 Cloneable
接口并重写 clone()
,否则会抛出异常。浅拷贝对于对象中有引用类型字段时,拷贝后两个对象会共享同一个引用字段。
如:
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 32 33
| public class Address implements Cloneable { private String city;
public Address(String city) { this.city = city; }
@Override protected Address clone() throws CloneNotSupportedException { return (Address) super.clone(); }
}
public class Person implements Cloneable { private String name; private Address address;
public Person(String name, Address address) { this.name = name; this.address = address; }
@Override protected Person clone() throws CloneNotSupportedException { Person cloned = (Person) super.clone(); return cloned; }
}
|
Person
的 clone()
是浅拷贝,拷贝的 Person
对象和原对象的 address
指向同一个 Address
实例。
- 若需完全拷贝(深拷贝),需要对引用字段也进行
clone()
。
第 7 章:static
与 final
关键字用法
7.1 静态属性与静态方法
static
修饰的成员属于类本身,而不是某个对象。
- 静态属性(变量)在内存中只有一份,所有对象共享。
- 静态方法可以直接通过类名调用,无需创建实例。
- 静态方法中不能访问非静态成员(因为非静态属于对象)。
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Counter { private static int count = 0;
public Counter() { count++; }
public static int getCount() { return count; } }
public class Main { public static void main(String[] args) { new Counter(); new Counter(); System.out.println(Counter.getCount()); } }
|
7.2 静态代码块
- 静态代码块用于类加载时执行一次的初始化操作。
- 适合做复杂的静态变量初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class Config { public static String ENV; public static int MAX_USERS;
static { ENV = "production"; MAX_USERS = 1000; System.out.println("Config 类被加载,静态代码块执行"); } }
public class Main { public static void main(String[] args) { System.out.println(Config.ENV); System.out.println(Config.MAX_USERS); } }
|
注意:静态代码块只执行一次,且在类被首次加载时执行。
7.3 final
类、方法、变量使用
final
可以修饰变量、方法、类,含义不同:
用法 |
说明 |
final 变量 |
常量,一旦赋值不可更改 |
final 方法 |
不可被子类重写 |
final 类 |
不能被继承的类(比如 String 类) |
如: |
|
7.3.1 final变量
1 2 3 4 5 6 7 8
| public class Constants { public static final double PI = 3.14159;
public static void main(String[] args) { System.out.println(Constants.PI); } }
|
7.3.2 final方法
1 2 3 4 5 6 7 8 9 10 11
| class Parent { public final void show() { System.out.println("Parent final method"); } }
class Child extends Parent { }
|
7.3.3 final类
1 2 3 4 5 6 7 8
| public final class Utility { public static void help() { System.out.println("Helping..."); } }
|
第 8 章:抽象类与接口
8.1 抽象类与抽象方法编写
- 抽象类 是不能被实例化的类,用于被继承。
- 抽象类中可以包含抽象方法(没有方法体,只定义方法签名),必须由子类实现。
- 抽象类也可以有普通方法和成员变量。
- 用
abstract
关键字声明。
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
| public abstract class Animal { protected String name;
public Animal(String name) { this.name = name; }
public abstract void sound();
public void sleep() { System.out.println(name + " is sleeping."); } }
public class Dog extends Animal { public Dog(String name) { super(name); }
@Override public void sound() { System.out.println(name + " says: Woof!"); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Animal dog = new Dog("Buddy"); dog.sound(); dog.sleep(); } }
|
8.2 接口的定义与实现
- 接口 是一种纯抽象的规范,只有方法签名和常量(Java 8+ 支持默认方法和静态方法)。
- 类通过
implements
关键字实现接口,必须实现接口中的所有抽象方法。
- 接口体现的是“能做什么”的能力,抽象类体现的是“是什么”的属性和行为。
如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public interface Flyable { void fly(); }
public interface Swimmable { void swim(); }
public class Duck implements Flyable, Swimmable { @Override public void fly() { System.out.println("Duck is flying."); }
@Override public void swim() { System.out.println("Duck is swimming."); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Duck duck = new Duck(); duck.fly(); duck.swim(); } }
|
8.3 接口多实现、向上转型
- 一个类可以实现多个接口(多继承的替代方案)。
- 可以将实现类对象向上转型为接口类型,利用多态调用接口方法。
- 接口变量只能调用接口中声明的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13
| public class Main { public static void main(String[] args) { Duck duck = new Duck();
Flyable f = duck; Swimmable s = duck;
f.fly(); s.swim();
} }
|
8.4 继承和实现的混合使用
- 一个类只能继承一个直接父类(单继承)。
- 但可以实现多个接口(多实现)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| public class Animal { public void eat() { System.out.println("Animal is eating"); } }
public interface Flyable { void fly(); }
public class Bird extends Animal implements Flyable { @Override public void fly() { System.out.println("Bird is flying"); } }
|
1 2 3 4 5 6 7
| public class Main { public static void main(String[] args) { Bird bird = new Bird(); bird.eat(); bird.fly(); } }
|
第 8 章:示例-地理要素系统
设计说明
- 抽象类
GeoFeature
(地理要素),定义公共属性和抽象方法
- 子类:
PointFeature
(点)、LineFeature
(线)、PolygonFeature
(多边形)
- 接口
Renderable
(可渲染),Calculable
(可计算面积或长度)
- 利用封装隐藏属性,提供 getter/setter
- 使用
static
统计创建的地理要素数量
- 使用
final
定义常量和禁止修改的方法
- 重写
toString()
, equals()
, clone()
- 演示多态和接口多实现
代码实现
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169
| public abstract class GeoFeature implements Cloneable { private String id; private String name; private static int featureCount = 0;
public GeoFeature(String id, String name) { this.id = id; this.name = name; featureCount++; }
public String getId() { return id; } public void setId(String id) { this.id = id; }
public String getName() { return name; } public void setName(String name) { this.name = name; }
public static int getFeatureCount() { return featureCount; }
public abstract void draw();
public final void showInfo() { System.out.println("GeoFeature: " + toString()); }
@Override public String toString() { return "ID=" + id + ", Name=" + name; }
@Override public boolean equals(Object obj) { if (this == obj) return true; if (!(obj instanceof GeoFeature)) return false; GeoFeature other = (GeoFeature) obj; return this.id.equals(other.id); }
@Override public GeoFeature clone() { try { return (GeoFeature) super.clone(); } catch (CloneNotSupportedException e) { throw new AssertionError(); } } }
interface Renderable { void render(); }
interface Calculable { double calculate(); }
class PointFeature extends GeoFeature implements Renderable { private double x, y;
public PointFeature(String id, String name, double x, double y) { super(id, name); this.x = x; this.y = y; }
public double getX() { return x; } public void setX(double x) { this.x = x; } public double getY() { return y; } public void setY(double y) { this.y = y; }
@Override public void draw() { System.out.println("Drawing Point at (" + x + "," + y + ")"); }
@Override public void render() { System.out.println("Rendering Point: " + getName()); }
@Override public String toString() { return super.toString() + ", Point(" + x + "," + y + ")"; } }
class LineFeature extends GeoFeature implements Renderable, Calculable { private double length;
public LineFeature(String id, String name, double length) { super(id, name); this.length = length; }
public double getLength() { return length; } public void setLength(double length) { this.length = length; }
@Override public void draw() { System.out.println("Drawing Line of length " + length); }
@Override public void render() { System.out.println("Rendering Line: " + getName()); }
@Override public double calculate() { return length; }
public double calculate(double scale) { return length * scale; }
@Override public String toString() { return super.toString() + ", Line length=" + length; } }
class PolygonFeature extends GeoFeature implements Renderable, Calculable { private double area;
public PolygonFeature(String id, String name, double area) { super(id, name); this.area = area; }
public double getArea() { return area; } public void setArea(double area) { this.area = area; }
@Override public void draw() { System.out.println("Drawing Polygon of area " + area); }
@Override public void render() { System.out.println("Rendering Polygon: " + getName()); }
@Override public double calculate() { return area; }
@Override public String toString() { return super.toString() + ", Polygon area=" + area; } }
|