作为一名从C++转型Java的开发者,我深刻理解初学者面对新语言时的困惑。Java作为一门面向对象的编程语言,其基础语法看似简单,但蕴含着许多独特的设计理念。让我们从一个最简单的Java类开始,逐步揭开Java编程的神秘面纱。
每个Java程序的起点都是一个类定义。下面这个Hello类展示了最基本的Java类结构:
java复制public class Hello {
public static void main(String[] args) {
// 程序入口
}
}
这段代码有几个关键点需要注意:
public是访问修饰符,表示这个类可以被任何其他类访问class关键字用于声明一个类Hello是类名,按照Java命名规范,类名应采用大驼峰式(首字母大写)main方法是Java程序的入口点,必须声明为public static void提示:在IntelliJ IDEA等现代IDE中,可以通过输入"psvm"快速生成main方法框架,这是提高编码效率的小技巧。
程序与用户的交互离不开输入输出操作。Java提供了简单易用的I/O机制:
java复制// 输出到控制台
System.out.println("Hello World"); // 快捷键:sout
// 从控制台读取输入
Scanner in = new Scanner(System.in);
int num = in.nextInt();
输出操作使用System.out对象,它是Java标准库提供的预定义对象。println方法会在输出内容后自动换行,如果不需要换行可以使用print方法。
输入操作需要先创建Scanner对象,它提供了多种方法来读取不同类型的输入:
nextInt()读取整数nextDouble()读取双精度浮点数nextLine()读取整行文本注意:使用Scanner时需要处理可能的输入异常,比如用户输入了非数字内容而程序尝试读取数字的情况。我们会在异常处理部分详细讨论这个问题。
Java是强类型语言,所有变量都必须先声明类型后使用。Java的基本数据类型分为四类八种:
整型:
byte (1字节)short (2字节)int (4字节,默认)long (8字节,后缀L)浮点型:
float (4字节,后缀F)double (8字节,默认)字符型:
char (2字节,Unicode)布尔型:
boolean (true/false)java复制int age = 25;
double price = 19.99;
char grade = 'A';
boolean isJavaFun = true;
Java中的类型转换分为自动类型转换和强制类型转换:
java复制int i = 100;
long l = i; // 自动转换
java复制double d = 100.04;
long l = (long)d; // 强制转换,小数部分丢失
注意:进行强制类型转换时要特别注意数据溢出的风险。例如将较大的long值强制转换为int时,高位数据会被截断。
类是Java面向对象编程的核心概念。一个类可以包含:
java复制public class Person {
// 字段
private String name;
private int age;
// 构造方法
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 方法
public void introduce() {
System.out.println("我叫" + name + ",今年" + age + "岁");
}
}
创建对象实例使用new关键字:
java复制Person p = new Person("张三", 25);
p.introduce();
Java支持方法重载(包括构造方法重载),即同一个类中可以有多个同名方法,只要它们的参数列表不同。
java复制public class Person {
private String name;
private int age;
// 无参构造
public Person() {
this("未知", 0); // 调用另一个构造方法
}
// 全参构造
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 部分参数构造
public Person(String name) {
this(name, 0);
}
}
构造方法重载提供了创建对象的不同方式,增加了类的灵活性。实际开发中,通常会提供多个构造方法以适应不同场景。
继承是面向对象的重要特性,Java使用extends关键字实现继承:
java复制public class Student extends Person {
private String school;
public Student(String name, int age, String school) {
super(name, age); // 调用父类构造
this.school = school;
}
@Override
public void introduce() {
super.introduce(); // 调用父类方法
System.out.println("我在" + school + "上学");
}
}
继承的特点:
super关键字可以访问父类的成员注意:方法重写时,子类方法的访问权限不能比父类更严格。例如,父类方法是public,子类重写时不能改为protected或private。
抽象类用abstract修饰,可以包含抽象方法(没有实现的方法)和具体方法:
java复制public abstract class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
// 抽象方法
public abstract void makeSound();
// 具体方法
public void eat() {
System.out.println(name + "正在吃东西");
}
}
抽象类的特点:
接口用interface定义,是完全抽象的"契约":
java复制public interface Flyable {
// 默认是public abstract
void fly();
// Java 8开始可以定义默认方法
default void land() {
System.out.println("正在降落");
}
// Java 8开始可以定义静态方法
static int getMaxAltitude() {
return 10000;
}
}
接口的特点:
public abstract(Java 8之前)public static final)implements关键字实现接口java复制public class Bird implements Flyable {
@Override
public void fly() {
System.out.println("鸟儿在飞翔");
}
}
在实际开发中,何时使用抽象类,何时使用接口?以下是一些指导原则:
使用抽象类的情况:
使用接口的情况:
随着Java的发展,接口的功能越来越强大,现在更倾向于"面向接口编程"的设计理念。
Java的异常处理基于五个关键字:try、catch、finally、throw、throws。
基本结构:
java复制try {
// 可能抛出异常的代码
} catch (ExceptionType1 e1) {
// 处理ExceptionType1类型的异常
} catch (ExceptionType2 e2) {
// 处理ExceptionType2类型的异常
} finally {
// 无论是否发生异常都会执行的代码
}
Java异常分为两大类:
检查型异常(Checked Exception):
非检查型异常(Unchecked Exception):
可以使用throw主动抛出异常,throws声明方法可能抛出的异常:
java复制public void deposit(double amount) throws IllegalArgumentException {
if (amount <= 0) {
throw new IllegalArgumentException("存款金额必须大于0");
}
// 正常处理逻辑
}
通过继承Exception或其子类可以创建自定义异常:
java复制public class InsufficientFundsException extends Exception {
private double shortage;
public InsufficientFundsException(double shortage) {
super("资金不足,还差" + shortage + "元");
this.shortage = shortage;
}
public double getShortage() {
return shortage;
}
}
使用自定义异常:
java复制public void withdraw(double amount) throws InsufficientFundsException {
if (amount > balance) {
throw new InsufficientFundsException(amount - balance);
}
balance -= amount;
}
java复制// try-with-resources示例
try (BufferedReader br = new BufferedReader(new FileReader("file.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
现代Java IDE提供了大量快捷键提高开发效率:
良好的代码风格对团队协作至关重要:
命名规范:
StudentManagergetStudentNameMAX_SIZE代码组织:
注释规范:
使用断点调试:
日志调试:
java复制import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyClass {
private static final Logger logger = LoggerFactory.getLogger(MyClass.class);
public void doSomething() {
logger.debug("开始处理...");
try {
// 业务逻辑
logger.info("处理成功");
} catch (Exception e) {
logger.error("处理失败", e);
}
}
}
字符串比较:
if (str == "hello")if ("hello".equals(str))浮点数比较:
if (a == b)if (Math.abs(a - b) < 0.00001)集合遍历时修改:
资源未关闭:
可变对象作为不可变使用:
对于有C++背景的开发者,转向Java时需要注意以下差异:
内存管理:
指针与引用:
多重继承:
运算符重载:
模板与泛型:
标准库差异:
理解这些差异有助于C++开发者更快适应Java开发。虽然语法上有相似之处,但两种语言的设计哲学和最佳实践有很大不同。