从C语言到Java

写在前面

记录一下笔者从C转到Java的过程,可以说是一个日记。?

正文

Java与C

首先,Java语言与C语言很直观的一个不同就在于这个public class的写法,

public class C_to_Java{
      public static void main(String[] args) {
        System.out.println("Hello, Java!");
    }
}

没有头文件,看起来像一个函数。C语言通过头文件调用例如printf的函数,而Java靠的是自带的

类就是“接口”,JVM自动管理依赖

当运行 java HelloWorld 时,JVM 会自动:
查找 System 类(在 rt.jar 标准库中)。
读取 out 属性(PrintStream)。
找到 println 方法的实现。

这整个过程都是在 运行时 完成的,不需要编译时就知道所有细节
(搜的,doge)

Java的 main 方法:程序的入口

所有 Java 程序都必须有一个 main 方法,它是程序启动的起点:

public static void main(String[] args) {
    System.out.println("Hello, Java!");
}

String[] args 是一个字符串数组,用来接收用户在命令行运行程序时输入的额外信息

Java的类

类是一个自定义的数据类型,它把数据(属性)和操作这些数据的函数(方法)打包在一起。

通常一个.java文件里只能有一个public类,(类似于结构体?)并且这个类名就是文件名,但可以有多个class类。因为Java编译器根据文件名去查找public。

Java和C的不同运行过程

Java和C语言一个是解释型语言一个是编译型语言,C语言生成的可执行文件直接在操作系统上运行

预处理 -> 编译 -> 汇编 -> 链接

.i       .s     .o     .exe

C 是静态编译语言:所有东西在编译时就确定了。(所谓静态编译,就是在程序运行之前,就已经把源代码完全翻译成机器码)
Java直接编译成字节码.class文件(类似于.o文件),字节码不是机器码,而是一种中间表示(Intermediate Representation, IR),可以跨平台运行。

【无预处理】 → 【无汇编】 → 【编译】 → 【动态链接】

编译生成 .class 字节码,运行时由 JVM 动态加载并执行。

Java类的相互调用

值得一提的是,Java的不同类之间可以相互调用,这不同于C语言。

类似于C语言的定义的头文件?

不同的是C 的头文件是“静态声明”,用于告诉编译器“函数长什么样”
Java 的 import 是“动态引用”,用于告诉 JVM “去哪里找类”。

只要是 public,且在同一个包中,或者通过 import 导入其所在包的类,就可以被访问。
假设有以下目录结构

src/
├── com/
│   └── example/ 主包
│       ├── Main.java
│       ├── Calculator.java
│       └── Printer.java
└── utils/ 另一个包
    └── MathUtils.java

1.同一个包内的类互相调用(无需 import)

Calculator.java(位于 com/example/)

// src/com/example/Calculator.java
public class Calculator {
    public int add(int a, int b) {
        return a + b;
    }

    public int multiply(int a, int b) {
        return a * b;
    }
}

Main.java(也在 com/example/)
// src/com/example/Main.java
public class Main {
    public static void main(String[] args) {
        // 直接使用同一包里的类,无需 import
        Calculator calc = new Calculator();
//由于 add 和 multiply 是 实例方法(Instance Methods),不是 static 的。
//所以必须通过一个对象来调用,如果方法是 static,就不需要创建对象
        int sum = calc.add(5, 3);          // 调用 add
        int product = calc.multiply(4, 6); // 调用 multiply

        System.out.println("5 + 3 = " + sum);
        System.out.println("4 × 6 = " + product);
    }
}
对于上面的静态方法和实例方法
概念 说明
对象(Object) 代表一个具体的实体,比如“一台计算器”
类(Class) 定义了“计算器”这个类型的所有属性和行为
实例方法 描述“这台计算器如何工作”(如加法、乘法)
静态方法 描述“计算器这个类型本身的特性”(如数学常数)

静态方法不也是传参数了?那它怎么是‘类型本身’的特性?”
答案是:
静态方法可以接收参数,但它不依赖于任何具体对象。它描述的是“这个类型能做什么”,而不是“这台机器正在做什么”

概念 比喻
实例方法 “这台计算器正在算一个加法” → 需要一台具体的计算器(对象)
静态方法 “所有计算器都支持加法” → 这是“计算器”这个类别本身的属性

实例方法:你必须有一台计算器才能用它
静态方法:你不需要任何设备,因为这是规则

(搜到,不再深究,主要在于用)

2.不同包的类调用(需要 import)

MathUtils.java(位于 utils/)

// src/utils/MathUtils.java
public class MathUtils {
    public static double squareRoot(double n) {
        return Math.sqrt(n);
    }

    public static boolean isEven(int n) {
        return n % 2 == 0;
    }
}
Main.java(修改后,调用 utils 包中的类)

// src/com/example/Main.java
import utils.MathUtils; // 导入外部包的类

public class Main {
    public static void main(String[] args) {
        // 现在可以使用 MathUtils 了
        System.out.println(MathUtils.squareRoot(16));     // 4.0
        System.out.println(MathUtils.isEven(7));         // false
        System.out.println(MathUtils.isEven(8));         // true
    }
}

3.一个类调用多个类(多个 import)

Printer.java(在 com/example/)

// src/com/example/Printer.java
import utils.MathUtils;

public class Printer {
    public void printInfo() {
        System.out.println("计算结果:");
        System.out.println("√16 = " + MathUtils.squareRoot(16));
        System.out.println("8 是偶数吗?" + MathUtils.isEven(8));
    }
}

Main.java(调用 Printer)

// src/com/example/Main.java
import utils.MathUtils;
import com.example.Printer;

public class Main {
    public static void main(String[] args) {
        Printer p = new Printer();
        p.printInfo();
    }
}

这里import找文件是在指定的源码目录里找,通常IDE已经自动完成了,不是在哪里都可以的哦

Java的面向对象

以下是搜的

封装:把“数据”和“行为”关进同一个盒子里

类似于C的函数,Java中的类就是这个盒子

它的好处是:你不能随便改别人的内部数据,只能通过它提供的“接口”来操作。

继承:子类可以“继承”父类的本领

写 C,想复用代码?得复制粘贴,或者用结构体嵌套。
现在写 Java,我可以直接说:“我是一个 ScientificCalculator,我继承自 Calculator。”

public class ScientificCalculator extends Calculator {
//这里extends是继承的意思
//类似于
//Dog 继承 Animal → 狗是一种动物。
//Car 继承 Vehicle → 汽车是一种交通工具。
    public double sin(double x) {
        return Math.sin(x);
    }
}

多态:同一个名字,不同表现
同一个方法名,根据调用的对象不同,表现不同。

// 父类
public class Animal {
    public void makeSound() {
        System.out.println("动物在叫");
    }
}

// 子类
public class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪!");
    }
}

public class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("喵喵喵!");
    }
}

@Override 是一个“提醒”注解,告诉编译器:“我这个方法是重写父类的方法”,表示重写父类。
抽象:定义“做什么”,不关心“怎么做”

以前写 C,我总得写完所有代码才能用。
现在写 Java,我可以先说:“我要一个 Shape,它必须有 area() 方法。”
具体怎么算,留给子类去决定。

public abstract class Shape {
    public abstract double area(); // 抽象方法,没有实现
}

public class Circle extends Shape {
    private double radius;

    public Circle(double r) {
        this.radius = r;
    }

    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

abstract是父类留给子类去实现的一个关键字,子类如果不实现,就会报错。

概念 一句话理解
封装 把数据和方法打包,保护内部细节
继承 子类自动拥有父类的能力
多态 同一个方法,不同对象,不同行为
抽象 定义“应该做什么”,不规定“怎么做”

写在最后

鉴于现在代码量不足,对于Java的很多方面的理解还很浅,以后再慢慢补充吧。不过这就是过渡的样子吧。

于2026.3.2 0:22

posted @ 2026-03-02 00:23  jackdanio  阅读(0)  评论(0)    收藏  举报