Java 新手开荒记:我的 7 天入门笔记
本文最后更新于39 天前,其中的信息可能已经过时,如有其他问题请留言
AI智能摘要
这篇文章是Java新手的学习笔记,介绍了Java的基础知识和基本语法。文章首先解释了Java是什么以及它是如何被Sun Microsystems公司开发的。接着,文章详细列出了Java的三个体系:JavaSE(J2SE)、JavaEE(J2EE)和JavaME(J2ME),并强调了它们的一些主要特性,如简单性、面向对象、分布式、健壮性、安全性、体系结构中立性、可移植性和解释型等。 文章还指导用户下载和安装Java开发工具包(JDK),并展示了如何创建一个Java项目。此外,文章还提到了编写Java程序时应注意的一些基本语法规则,例如大小写敏感、类名首字母大写、方法名以小写字母开头等。最后,文章还提到了Java的标识符规则,包括所有组成部分都需要名字,所有的标识符都应该以字母、美元符或下划线开始,且首字符之后可以是字母、美元符、下划线或数字的任何字符组合,关键字不能用作标识符,标识符是大小写敏感的,合法标识符举例和非法标识符举例也进行了说明。

Java_day01

Java基础

Java简介

Java 是由 Sun Microsystems 公司于 1995 年 5 月推出的 Java 面向对象程序设计语言和 Java 平台的总称。由 James Gosling和同事们共同研发,并在 1995 年正式推出。

后来 Sun 公司被 Oracle (甲骨文)公司收购,Java 也随之成为 Oracle 公司的产品。

Java分为三个体系:

  • JavaSE(J2SE)(Java2 Platform Standard Edition,java平台标准版)
  • JavaEE(J2EE)(Java 2 Platform,Enterprise Edition,java平台企业版)
  • JavaME(J2ME)(Java 2 Platform Micro Edition,java平台微型版)。

主要特性

  • Java 语言是简单的
  • Java 语言是面向对象的
  • Java语言是分布式的
  • Java 语言是健壮的
  • Java语言是安全的
  • Java 语言是体系结构中立的
  • Java 语言是可移植的
  • Java 语言是解释型的
  • Java 是高性能的
  • Java 语言是多线程的
  • Java 语言是动态的

下载JDK

通过链接Java Downloads | Oracle下载

下载好后,按照提示一步步安装

选择安装位置

关闭即可

验证安装

win+R输入cmd回车打开运行框输入: java –version , 返回下方结果就是安装好了

安装IDEA

进入官网Download IntelliJ IDEA

单击Download开始下载windows版本的IDEA

选择安装位置

按需要勾选

单击安装即可

等待安装完成

创建一个Java项目

选好jdk后创建

然后就会创建一个有示范代码的java项目

Hello World程序

在src目录下新建目录,创建一个Java类

输入类名Hello

输入下方代码

package java_day01;

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

执行输入Hello , Java

基本语法

编写 Java 程序时,应注意以下几点:

  • 大小写敏感:Java 是大小写敏感的,这就意味着标识符 Hello 与 hello 是不同的。
  • 类名:对于所有的类来说,类名的首字母应该大写。如果类名由若干单词组成,那么每个单词的首字母应该大写,例如 MyFirstJavaClass 。
  • 方法名:所有的方法名都应该以小写字母开头。如果方法名含有若干单词,则后面的每个单词首字母大写。
  • 源文件名:源文件名必须和类名相同。当保存文件的时候,你应该使用类名作为文件名保存(切记 Java 是大小写敏感的),文件名的后缀为 .java。(如果文件名和类名不相同则会导致编译错误)。
  • 主方法入口:所有的 Java 程序由 public static void main(String[] args) 方法开始执行。

Java 标识符

Java 所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。

关于 Java 标识符,有以下几点需要注意:

  • 所有的标识符都应该以字母(A-Z 或者 a-z),美元符($)、或者下划线(_)开始
  • 首字符之后可以是字母(A-Z 或者 a-z),美元符($)、下划线(_)或数字的任何字符组合
  • 关键字不能用作标识符
  • 标识符是大小写敏感的
  • 合法标识符举例:age、$salary、_value、__1_value
  • 非法标识符举例:123abc、-salary

枚举类型

Java 5.0引入了枚举,枚举限制变量只能是预先设定好的值。使用枚举可以减少代码中的 bug。

package java_day01;

class FreshJuice {
    enum FreshJuiceSize{ SMALL, MEDIUM , LARGE }
    FreshJuiceSize size;
}

public class Enum {
    public static void main(String[] args){
        FreshJuice juice = new FreshJuice();
        juice.size = FreshJuice.FreshJuiceSize.MEDIUM ;
        System.out.println(juice.size);
    }
}

关键字

abstract

java语言常用关键字:

  • abstract 用于声明一个抽象类抽象方法

抽象类

抽象类使用 abstract 关键字声明。抽象类可以包含普通的方法和属性,也可以包含抽象方法。抽象方法是没有具体实现的方法,它只有方法名,没有方法体。抽象类的语法如下:

public abstract class MyClass {
   // 抽象类的属性和方法
}

抽象类的一个示例:

public abstract class Shape {
   protected int x;
   protected int y;
   public Shape(int x, int y) {
       this.x = x;
       this.y = y;
   }
   public abstract double getArea();
}

在这个例子中,Shape 是一个抽象类,它包含一个抽象方法 getArea()

抽象方法

抽象方法使用 abstract 关键字声明,没有方法体,只有方法的声明。抽象方法必须在子类中被实现,否则子类也必须被声明为抽象类。抽象方法的语法如下:

public abstract void myMethod();

抽象方法的一个示例:

public abstract class Shape {
   public abstract double getArea();
}

子类实现抽象方法

子类继承抽象类时,必须实现抽象类中的所有抽象方法。例如:

public class Circle extends Shape {
   private int radius;
   public Circle(int x, int y, int radius) {
       super(x, y);
       this.radius = radius;
   }
   @Override
   public double getArea() {
       return Math.PI * radius * radius;
   }
}

在这个例子中,Circle 类继承了 Shape 类,并实现了 getArea() 方法。

使用抽象类和抽象方法的好处

使用抽象类和抽象方法可以让我们更好地组织代码,实现多态和代码复用,同时也可以在设计上保证代码的可维护性和可扩展性。

注意事项

  1. 抽象类不能被实例化。
  2. 抽象类可以包含构造方法。
  3. 抽象类中不一定包含抽象方法,但包含抽象方法的类一定是抽象类。
  4. 抽象方法不能有方法体,必须在子类中实现。

通过理解和使用 abstract 关键字,可以更好地设计和实现面向对象的程序,提高代码的灵活性和可维护性。

native

在Java编程中,native关键字用于声明一个方法是由本地代码(通常是C或C++)实现的。这意味着该方法的具体实现不是用Java编写的,而是由底层的本地代码提供。这种方法允许Java程序与本地代码进行交互,实现更高效的操作,或者访问底层系统资源。

要声明一个native方法,只需在Java方法的声明中加上native关键字,并且不需要提供方法的实现。例如:

public native void nativeMethod();

在这个例子中,nativeMethod()是一个native方法,它的具体实现将在本地代码中提供。

为了使用native方法,必须在Java程序中加载本地库,并确保本地库中包含了所需的函数。本地库可以使用Java的JNI(Java Native Interface)来编写,并在程序运行时通过System.loadLibrary()方法加载。下面是一个简单的示例:

public class NativeExample {
   static {
       System.loadLibrary("nativeLibrary");
   }
   public native void nativeMethod();
   public static void main(String[] args) {
       new NativeExample().nativeMethod();
   }
}

在这个示例中,nativeMethod()将在名为nativeLibrary的本地库中实现。

实现步骤

  1. 创建包含本地方法的类:编写一个包含native方法的Java类。
  2. 编译运行:使用javac编译Java类。
  3. 获得头文件:使用javah生成包含本地方法声明的头文件。
  4. 实现头文件的声明方法:在C或C++中实现头文件中声明的方法。
  5. 生成动态链接库:将C或C++文件编译为动态链接库(如DLL文件)。
  6. 再次运行Java类:使用System.loadLibrary()加载动态链接库,并运行Java类。

注意事项

使用native方法虽然可以提高程序的性能,但也带来了潜在的安全隐患和跨平台兼容性问题。因此,除非必要,否则应尽量避免使用native方法。

throw

在 Java 中,throw 关键字用于显式地抛出一个异常。通过使用 throw 语句,程序员可以在代码中手动引发异常,从而中止当前的执行流,并将控制权交给相应的 catch 块来处理该异常。

throw 语句的基本语法如下:

throw new ExceptionInstance;

其中,ExceptionInstance 是一个异常类的实例。需要注意的是,throw 语句每次只能抛出一个异常实例。

以下是一个使用 throw 语句抛出异常的示例:

class Main {
   public static void divideByZero() {
       throw new ArithmeticException("试图除以0");
   }
   public static void main(String[] args) {
       divideByZero();
   }
}

输出结果:

Exception in thread "main" java.lang.ArithmeticException: 试图除以0
   at Main.divideByZero(Main.java:3)
   at Main.main(Main.java:7)

在这个示例中,我们显式地抛出了一个 ArithmeticException 异常。

抛出检查异常

对于检查异常(Checked Exception),必须在方法声明中使用 throws 关键字来声明该方法可能抛出的异常类型。例如:

import java.io.*;
class Main {
   public static void findFile() throws IOException {
       throw new IOException("文件未找到");
   }
   public static void main(String[] args) {
       try {
           findFile();
       } catch (IOException e) {
           System.out.println(e.getMessage());
       }
   }
}

输出结果:

文件未找到

在这个示例中,findFile() 方法使用传递给其构造函数的消息抛出了一个 IOException。由于它是一个检查异常,因此必须在 throws 子句中指定它。

自定义异常类

在大多数情况下,创建自定义异常类可以帮助更好地描述和处理特定的异常情况。以下是一个自定义异常类的示例:

class AuctionException extends Exception {
   public AuctionException(String message) {
       super(message);
   }
}

通过创建自定义异常类,可以在代码中更准确地描述异常。

总结

通过使用 throw 关键字,Java 程序员可以显式地抛出异常,从而中止当前的执行流,并将控制权交给相应的 catch 块来处理该异常。对于检查异常,必须在方法声明中使用 throws 关键字来声明该方法可能抛出的异常类型。自定义异常类可以帮助更好地描述和处理特定的异常情况。

strictfp

在Java中,strictfp关键字用于确保浮点计算的结果在不同的处理器平台上保持一致。由于不同处理器可能使用不同的浮点寄存器(例如80位和64位),这可能导致浮点计算结果的不一致。使用strictfp关键字可以强制Java虚拟机按照IEEE 754浮点标准进行计算,从而保证结果的一致性。

使用示例

以下是一个使用strictfp关键字修饰方法的示例:

public class StrictfpTest {
   public static strictfp void main(String[] args) {
       float aFloat = 0.6710339f;
       double aDouble = 0.04150553411984792d;
       double sum = aFloat + aDouble;
       float quotient = (float)(aFloat / aDouble);
       System.out.println("float: " + aFloat);
       System.out.println("double: " + aDouble);
       System.out.println("sum: " + sum);
       System.out.println("quotient: " + quotient);
   }
}

在这个例子中,main方法中的所有指令都将使用严格的浮点计算。

适用范围

strictfp关键字可以用来修饰类、接口或方法。使用strictfp关键字标记的方法必须使用严格的浮点计算来生成可再生的结果。严格的浮点计算表示浮点计算完全依照浮点规范IEEE 754来执行。

性能影响

需要注意的是,采用strictfp关键字会对中间结果进行截断操作,而截断操作需要消耗时间,因此在计算速度上比不使用strictfp要慢。然而,对于大多数程序来说,浮点溢出并不是一个大问题。

结论

尽管strictfp关键字在Java 17中已经变得不再必要,但它在确保浮点计算结果一致性方面仍然具有重要意义。

transient

transient 是 Java 中用于控制序列化行为的关键字。它的主要作用是阻止某个实例变量被序列化,即在对象持久化时,该字段不会被写入到序列化流中。

当一个类实现了 Serializable 接口时,默认所有非静态成员变量都会被序列化。但在实际开发中,有些字段(如密码、银行卡号等敏感信息)不希望被持久化或通过网络传输,这时就可以用 transient 修饰。

基本用法示例

import java.io.*;
class User implements Serializable {
   private static final long serialVersionUID = 1L;
   private String username;
   private transient String password; // 不会被序列化
   public User(String username, String password) {
       this.username = username;
       this.password = password;
   }
   public String toString() {
       return "username: " + username + ", password: " + password;
   }
}
public class TransientDemo {
   public static void main(String[] args) throws Exception {
       User user = new User("Alexia", "123456");
       // 序列化
       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.obj"));
       oos.writeObject(user);
       oos.close();
       // 反序列化
       ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.obj"));
       User deserialized = (User) ois.readObject();
       ois.close();
       System.out.println(deserialized);
   }
}

运行结果中 password 会变为 null,说明它未被序列化。

注意事项

  1. 仅作用于变量:不能修饰方法、类,本地变量也不能用 transient
  2. 静态变量不受影响:静态字段本身不参与序列化,与是否加 transient 无关。反序列化后静态变量值来自当前 JVM,而非序列化数据。
  3. Externalizable 特例:如果类实现的是 Externalizable 接口,并在 writeExternal 方法中手动序列化 transient 字段,该字段依然会被写入。

适用场景

  • 屏蔽敏感信息(密码、密钥等)
  • 避免序列化无意义或不可序列化的对象(如线程、Socket 等)
  • 减少序列化数据体积,提高传输效率

这样,transient 可以帮助我们在序列化过程中更好地控制数据安全与性能。

protected

在 Java 中,protected 是一种访问修饰符,用于控制类成员(字段、方法、构造函数)的可见性。它的主要作用是允许子类和同一包内的类访问被修饰的成员,但在不同包的非子类中不可见。

protected 的可见性规则

  1. 同一包内protected 修饰的成员对同一包内的所有类可见。
  2. 子类访问:即使子类与父类不在同一包中,子类也可以访问从父类继承的 protected 成员,但只能通过子类自身的实例访问,而不能通过父类实例或其他子类实例访问。
  3. 跨包限制:如果父类和子类不在同一包中,父类无法访问子类中特有的 protected 成员。

示例代码

以下是一个关于 protected 的简单示例,展示其在不同场景下的行为:

// 父类在包 A 中
package A;
public class Parent {
   protected void display() {
       System.out.println("Protected method in Parent class");
   }
}
// 子类在包 B 中
package B;
import A.Parent;
public class Child extends Parent {
   public void callDisplay() {
       // 子类可以访问继承的 protected 方法
       display();
   }
}
// 测试类在包 B 中
package B;
public class Test {
   public static void main(String[] args) {
       Child child = new Child();
       child.callDisplay(); // 输出: Protected method in Parent class
       Parent parent = new Parent();
       // parent.display(); // 编译错误:无法通过父类实例访问 protected 方法
   }
}

注意事项

  1. 跨包访问限制:如果子类和父类不在同一包中,子类只能通过自身实例访问继承的 protected 成员,不能通过父类实例或其他子类实例访问。
  2. 构造函数的 protected 修饰protected 构造函数允许子类调用,但限制了非子类直接实例化父类。
  3. 内部类的 protected 修饰protected 的内部类只能在同一包内或子类中被访问,但其默认构造函数的可见性也会受到限制。

总结

protected 是 Java 中较为复杂的访问修饰符之一。它在包内和子类中提供了灵活的访问权限,但在跨包场景中有严格的限制。理解其规则有助于在设计类的继承关系时更好地控制访问权限。

synchronized

synchronized 是Java内置的线程同步机制,用于在多线程环境下保证原子性、可见性和有序性。它通过**对象监视器锁(Monitor)**来控制多个线程对共享资源的互斥访问,防止竞态条件。

核心作用

  • 原子性:确保同步代码块在同一时刻只被一个线程执行。
  • 可见性:线程释放锁前会将工作内存数据刷新到主内存,其他线程获取锁时会读取最新值。
  • 有序性:禁止同步块内的指令重排序,符合JMM的happens-before规则。

常用用法

  • 修饰实例方法(锁对象为this
public synchronized void deposit(double amount) {
   balance += amount;
}

适用于保护实例变量,多个实例互不影响。

  • 修饰静态方法(锁对象为Class对象)
public static synchronized void increment() {
   count++;
}

适用于类级别共享资源,所有实例共用一把锁。

  • 同步代码块(可指定任意锁对象)
private final Object lock = new Object();
public void update() {
   synchronized (lock) {
       // 仅同步关键代码
   }
}

可细化锁粒度,减少锁竞争。

底层原理

  • 编译后生成monitorentermonitorexit字节码指令。
  • JVM通过对象头的Mark Word记录锁状态(无锁、偏向锁、轻量级锁、重量级锁)。
  • 锁升级过程:无锁 → 偏向锁 → 轻量级锁 → 重量级锁,升级不可逆。
  • JDK 1.6后引入偏向锁和轻量级锁,大幅优化性能。

性能优化建议

  • 减小锁粒度:拆分锁对象,允许并行访问不同资源。
  • 缩短锁持有时间:将耗时操作移出同步块。
  • 锁消除:利用JVM逃逸分析移除不必要的锁。
  • 锁粗化:合并连续的加锁操作,减少锁获取次数。

常见问题

  • 死锁:多个线程循环等待对方持有的锁,可通过固定加锁顺序或tryLock避免。
  • 错误锁对象:使用可变对象或字符串常量池对象作为锁可能导致同步失效,应使用final独立锁对象。
  • 高竞争性能瓶颈:可用Atomic类(CAS乐观锁)、ReadWriteLock或并发容器替代。

与Lock接口对比

  • synchronized:隐式获取/释放锁,不可中断,不支持超时,代码简洁,JVM自动优化。
  • Lock:显式获取/释放锁,可中断、可超时、可公平锁,支持多个条件变量,适合复杂同步需求。

示例:同步代码块防止竞态

public class Counter {
   private int count = 0;
   private final Object lock = new Object();
   public void increment() {
       synchronized (lock) {
           count++;
       }
   }
   public int getCount() {
       synchronized (lock) {
           return count;
       }
   }
}

该实现确保count在多线程环境下安全递增。

synchronized简单易用,适合大多数线程安全需求;在高并发或复杂控制场景下,可结合Lock或无锁结构提升性能。

volatile

volatile 是Java中的轻量级同步机制,主要用于保证多线程环境下共享变量的可见性以及防止指令重排序,但不保证原子性。它通过在底层插入**内存屏障(Memory Barrier)**来实现语义,确保一个线程对变量的修改能立即被其他线程看到,并禁止特定类型的重排序。

核心特性

  • 可见性:线程写入volatile变量会立即刷新到主内存,其他线程读取时直接从主内存获取最新值。
  • 有序性:禁止与volatile变量相关的指令重排序,保证执行顺序符合预期。
  • 无原子性:复合操作(如i++)仍需加锁或使用原子类。

典型应用场景

  1. 状态标记(线程停止信号)
  2. 双重检查锁定单例模式
  3. 安全发布对象

示例:状态标记

public class ShutdownHook extends Thread {
   private volatile boolean shutdownRequested = false;
   public void run() {
       while (!shutdownRequested) {
           // 业务逻辑
       }
   }
   public void shutdown() {
       shutdownRequested = true;
   }
}

此处volatile确保shutdownRequested的修改对所有线程立即可见。

示例:双重检查锁定单例

public class Singleton {
   private static volatile Singleton instance;
   public static Singleton getInstance() {
       if (instance == null) {
           synchronized (Singleton.class) {
               if (instance == null) {
                   instance = new Singleton();
               }
           }
       }
       return instance;
   }
}

volatile防止对象初始化过程的指令重排,避免其他线程获取到未完全初始化的对象。

与synchronized对比

  • volatile:仅保证可见性和有序性,无锁,高性能,适合简单状态标记。
  • synchronized:保证可见性+原子性+互斥性,有锁,适合复杂同步逻辑。

注意事项

  • 不适用于需要原子性的场景(如计数器累加)。
  • 适合修饰布尔、引用等简单类型。
  • 过度使用会影响性能,应在确有可见性或重排序风险时使用。

总结volatile是并发编程中解决可见性有序性问题的利器,配合happens-before规则可构建高效的线程安全机制,但需结合锁或原子类来处理原子性需求。

常见关键字

classconstbreakbytesuper
enumextendscontinueedefaulttry
ifimplementsfinalfinallycase
shortnew importinstanceofdo
booleanstaticpackageprivatefloat
intswitchvoidcatchdouble
forinterfacepubliccharelse
gotolongreturnthiswhile

说明: true,false,null等单词在Java语言中不属于关键字,而属于保留字,它们也不能被用来命名标识符。

标识符命名规则

  • 标识符可以由多个单词连接而成 如 photoprice
  • 类名的命名:每个单词的首字母要大写,其他字母小写。 如 TeacherHelloWorld
  • 方法名和变量名:如果名称只有一个单词就全小写,如果由多个单词组成,除了第一个单词以外其他单词都首字母大写 如stuName
  • 常量名:所有字母大写,多个单词用_连接 如 PAI MIN_VALUE
  • 包名:所有单词的所有字母都小写 如 com.example

整理资料不易,觉得有帮助可以投喂下博主哦~感谢!
作者:Hueil
版权声明:本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议
转载请注明 文章地址 及 作者 哦~
暂无评论

发送评论 编辑评论


                
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇