java的特殊语法点,与常规语言相异的点
2026/9/13 21:15:19 网站建设 项目流程

特点一,“万物”皆是类和封装

1,包装文件

先从你最熟悉的 C 语言开始

学 C 的时候,可能会写:

#include <stdio.h> int main() { printf("Hello"); return 0; }

这里的思维比较“直接”:

程序

函数

执行代码

例如:

int add(int a, int b) { return a + b; }

你可以直接定义一个函数。


Java 不喜欢你把一个普通函数直接扔在文件里。

比如你不能这样:

int add(int a, int b) {

return a + b;

}

Java 会报错。

Java 更倾向于:

把代码组织到类里面。

所以你要写:

class Calculator { int add(int a, int b) { return a + b; } }

然后:

Calculator calculator = new Calculator(); int result = calculator.add(10, 20);

你可以把它理解成:

C:

函数

直接调用

Java:

对象

对象的方法

调用

2,构造方法

构造方法最常见的用途:创建对象的时候直接传数据

比如我们不想每次写

Student student = new Student(); student.name = "张三"; student.age = 18;

而是希望:

Student student = new Student("张三", 18);

那么可以写

class Student { String name; int age; Student(String name, int age) { this.name = name; this.age = age; } }

然后:

Student student = new Student("张三", 18);

这就是构造方法非常重要的用途。

这里需要理解this

class Student { String name; int age; Student(String name, int age) { this.name = name; this.age = age; } }

这里有两个name

this.name

当前对象的成员变量。

name

构造方法的参数。

所以:

this.name = name;当前对象的name ← 外部传进来的name

3,封装

封装的核心:把数据藏起来

我们可以这样写:

class Student { private String name; private int age; }

private,就是 Java 封装最核心的东西之一。

这个成员只能在当前类内部访问。

所以外部:

Student s = new Student(); s.age = -100;

会直接报错。

因为:

Student类外部

private age

不允许直接访问


那外部怎么修改 age?

这时候就需要给外部提供一个“合法入口”。

class Student { private String name; private int age; public void setAge(int age) { if (age >= 0) { this.age = age; } } public int getAge() { return age; } }

外部:

Student s = new Student(); s.setAge(20); System.out.println(s.getAge());

这样就变成:

外部代码

setAge(20)

Student内部检查

age = 20

所以封装不是简单的“private + getter/setter”

这是初学 Java 时非常容易产生的误解。

属性 private,然后提供 getter/setter,这就是封装。

这其实只是最常见的实现方式

真正的思想是:

隐藏对象内部的实现细节,只向外部暴露必要的操作接口。

比如:

class BankAccount { private double money; public void withdraw(double money) { if (money <= 0) { return; } if (money > this.money) { return; } this.money -= money; } }

特点二,变量方法修饰权限

python中只有简单的口头约定和名义上的私有(其实还是可以通过_object_访问)

而java对不同内容进行了不同的规定其中·包含了public,protect,空着,private

访问权限依次提升

一张图总结,先来说一下什么是一个包,什么不是一个包,就是是否在同一个包文件夹下,也可以直接看代码的初始行会带一个package表示目录

特点三,继承多态接口

1,继承

比如我们有:

动物

├── 狗

├── 猫

└── 鸟

动物都有,名字年龄,吃东西,睡觉

但是狗还有:

猫还有:

如果我们每个类都重新写:全部重复了。

所以我们可以把公共部分提取出来:

class Animal { String name; int age; void eat() { System.out.println("吃东西"); }

然后:

class Dog extends Animal { void bark() { System.out.println("汪汪"); } }

Dog 继承 Animal

所以继承就是对复用代码的继承和对新内容的扩增

2,对父类方法重写 @Override

例如:

class Dog extends Animal { @Override void makeSound() { System.out.println("汪汪"); } }

这里 Dog 把父类的:

makeSound()

重新实现了一遍。

这叫:

方法重写(Override)


十一、@Override是什么?

你经常会看到:

@Override public void xxx() { }

它是一个注解

意思是告诉 Java:

“我这个方法是准备重写父类的方法。”


3,重载和重写千万别搞混

这个是 Java 初学者的高频坑。

Overload:重载

同一个类:

void test(int a) {}

void test(String a) {}

方法名一样,参数不同。

叫:

方法重载

继承还有一个非常重要的东西:super

super

它可以理解为:

代表父类部分。

例如:你想用父类的name内容,就可以直接super.name

class Animal { String name = "动物"; } class Dog extends Animal { String name = "狗"; void test() { System.out.println(name); System.out.println(super.name); } } super.name

super():调用父类构造方法

这个非常重要。

例如:

class Animal { String name = "动物"; } class Dog extends Animal { String name = "狗"; void test() { System.out.println(name); System.out.println(super.name); } } super.name

执行:Dog dog = new Dog();两个都会输出

创建子类对象的时候,要先完成父类部分的初始化。

可以理解成:

new Dog()

先初始化 Animal

再初始化 Dog

而且:

子类构造方法第一行默认会调用super()


Java 和 Python 的继承有什么区别?

Python 你可能见过:

class Dog(Animal): pass Java: class Dog extends Animal { }

思想基本一样。但是 Java 有一个很重要的限制:

Java 的类只能直接继承一个父类。

比如:

class Dog extends Animal {

}

可以。

但是:

class Dog extends Animal, Pet {

}

不允许。

也就是说:

Java,一个类

只能有一个直接父类

这叫:

单继承


那 Java 如果想实现多个能力怎么办?

Java 使用:

接口 Interface

实现接口

接口和继承结合起来,就是 Java 面向对象很重要的一部分。接口内容后面会细致的讲解


继承和封装到底是什么关系?

现在把你刚学的两个知识放在一起:

封装

private

隐藏内部数据

通过方法控制访问

继承

extends

复用父类代码

扩展父类功能


4,多态

先看一个让人疑惑的代码

我们刚才有:

class Animal {

public void eat() {

System.out.println("动物吃东西");

}

}

class Dog extends Animal {

@Override

public void eat() {

System.out.println("狗吃狗粮");

}

public void bark() {

System.out.println("汪汪");

}

}

现在:

Animal a = new Dog();

你可能第一反应:

a明明是Animal类型,为什么后面new Dog()

这正是多态的核心。

先把这一句话吃透

Animal a = new Dog();

实际上可以拆成两部分:

Animal a

变量 a 的类型是 Animal

new Dog()

真正创建出来的对象是 Dog

所以:

左边决定“你能看到什么”,右边决定“实际上是谁”。

这是理解 Java 多态最重要的一句话。

假设:

class Animal { public void makeSound() { System.out.println("动物叫"); } } class Dog extends Animal { @Override public void makeSound() { System.out.println("汪汪"); } } class Cat extends Animal { @Override public void makeSound() { System.out.println("喵喵"); } }

现在:

Animal a1 = new Dog(); Animal a2 = new Cat(); a1.makeSound(); a2.makeSound();

结果:

汪汪

喵喵

那怎么调用 Dog 特有的方法?

可以进行:

向下转型

但是这里有一个问题,类型转变前提是我得是父子类关系,所以需要判断,不允许任意一个类随便转变

if (animal instanceof Dog) { Dog dog = (Dog) animal; dog.bark(); }

5,多态最大的实际价值:解耦

这个词你以后学 Java Web 会经常遇到:

解耦

比如你写:

public void feedDog(Dog dog) { dog.eat(); }

这个方法只能接收:

Dog

以后如果想支持 Cat:

public void feedCat(Cat cat)

又要写一个。

但是如果:

public void feedAnimal(Animal animal) { animal.eat(); }

那么:

feedAnimal(new Dog()); feedAnimal(new Cat()); feedAnimal(new Bird());

全部可以。

因为:

Dog ──┐

Cat ──┼──> Animal

Bird ─┘

所以调用者不需要知道具体是哪一种动物。

你现在应该建立的完整思维

把三个概念串起来:

面向对象

├── 封装

│ ↓

│ 保护数据和内部实现

├── 继承

│ ↓

│ 复用和扩展已有类

└── 多态

不同子类产生不同表现,实际上它们是连起来的。

6,接口

先说接口到底是什么

你可以先把接口理解成:

接口是一份“规范”或者“合同”,规定一个类必须具备哪些能力。

例如我们规定:

所有会飞的东西,都必须具备fly()能力。

那么可以定义:

interface Flyable void fly(); }

注意这里:

void fly();

没有方法体。它表达的是:(其实可以理解为这里其实是 public abstract void fly())

abstract是一个修饰指的是这是一个抽象类不需要内部填写具体内容

你只要实现 Flyable,就必须提供 fly() 的具体实现。

然后:

class Bird implements Flyable { @Override public void fly() { System.out.println("鸟在飞"); } }

这就是接口最核心的思想。他和继承最大区别就是

接口可以是多个

7,接口 + 多态实现分块

这才是接口真正强大的地方。例如:

interface Animal { void eat(); } class Dog implements Animal { @Override public void eat() { System.out.println("狗吃狗粮"); } } class Cat implements Animal { @Override public void eat() { System.out.println("猫吃鱼"); } }

然后:

Animal a1 = new Dog(); Animal a2 = new Cat(); a1.eat(); a2.eat();

输出:

狗吃狗粮

猫吃鱼

这和你刚才学的:

Animal a = new Dog();

本质上是一样的。区别只是,之前:Animal 是父类现在:Animal 是接口

所以你可以把它理解成:

接口是实现多态的重要工具。

拿这个javaweb举例,Java Web 特别喜欢接口

假设你正在写一个用户系统。

你定义:

interface UserService { void addUser(); void deleteUser(); void updateUser(); }

然后:

class UserServiceImpl implements UserService { @Override public void addUser() { // 具体实现 } @Override public void deleteUser() { // 具体实现 } @Override public void updateUser() { // 具体实现 } }

然后其他代码:

UserService service = new UserServiceImpl();

调用者只需要知道:

UserService

不需要关心:

UserServiceImpl

具体是怎么实现的。

8,接口的default

default的作用

主要是为了解决:

接口升级时,不影响原来的实现类。

例如原来接口:

interface Animal {

void eat();

}

后来接口增加:

default void sleep() {

System.out.println("睡觉");

}

以前实现Animal的类不需要修改代码,也可以正常使用。

所以:

default方法

接口可以增加新方法

原来的实现类不用强制修改

解决接口升级问题


3. 默认方法和抽象方法的区别

// 抽象方法

void show();

// 默认方法

default void show() {

System.out.println("show");

}

区别:

  • 抽象方法:没有方法体,实现类必须重写。

  • 默认方法:有方法体,实现类可以不重写。

注意,如果实现了多个接口,多个接口中存在相同名字的默认方法,子类就必须对该方法进行重写


4. 如果实现类要重写默认方法

去掉default

9,匿名内部类

有些类只需要一次匿名写入,比如这里重写一个接口的代码,不需要重新建立一个类inplements接口,再重写再创建再重写

特点四,io操作

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询