Hello World

Java和JavaScript虽然有不同的特点,但在一些概念和知识点上是相似的。本文从JavaScript开发者的角度出发,帮助你理解Java基础知识(反过来也行)。

//  解释型
console.log("Hello, World!");
// 编译型
public class HelloWorld {
  // 所有的 Java 程序由 public static void main(String[] args) 方法开始执行
  public static void main(String[] args) {
    System.out.println("Hello, World!");
  }
}

一、数据类型

类型

  • js
let undefinedVar; // undefined类型
let nullVar = null; // null类型
let boolVar = true; // boolean类型
let numVar = 10; // number类型
let strVar = 'Hello'; // string类型
let symVar = Symbol('foo'); // symbol类型
let objVar = {name: 'Tom'}; // object类型
let arrVar = [1, 2, 3]; // object类型中的数组
let funcVar = function() {}; // object类型中的函数
console.log(typeof undefinedVar); // 输出"undefined"
console.log(typeof nullVar); // 输出"object"
console.log(typeof boolVar); // 输出"boolean"
console.log(typeof numVar); // 输出"number"
console.log(typeof strVar); // 输出"string"
console.log(typeof symVar); // 输出"symbol"
console.log(typeof objVar); // 输出"object"
console.log(typeof arrVar); // 输出"object"
console.log(typeof funcVar); // 输出"function"
  • ts
    TypeScript是JavaScript的超集,因此支持所有JavaScript的数据类型,同时增加了一些新的数据类型,如元组、枚举等。
let undefinedVar: undefined = undefined; // undefined类型
let nullVar: null = null; // null类型
let boolVar: boolean = true; // boolean类型
let numVar: number = 10; // number类型
let strVar: string = 'Hello'; // string类型
let symVar: symbol = Symbol('foo'); // symbol类型
let objVar: object = {name: 'Tom'}; // object类型
let arrVar: number[] = [1, 2, 3]; // 数组类型
let funcVar: Function = function() {}; // 函数类型
console.log(typeof undefinedVar); // 输出"undefined"
console.log(typeof nullVar); // 输出"object"
console.log(typeof boolVar); // 输出"boolean"
console.log(typeof numVar); // 输出"number"
console.log(typeof strVar); // 输出"string"
console.log(typeof symVar); // 输出"symbol"
console.log(typeof objVar); // 输出"object"
console.log(typeof arrVar); // 输出"object"
console.log(typeof funcVar); // 输出"function"
  • java
// 基本数据类型
byte byteVar = 123;
short shortVar = 12345;
int intVar = 123456789;
long longVar = 123456789012345L;
float floatVar = 1.23f;
double doubleVar = 1.23456789;
char charVar = 'A';
boolean booleanVar = true;
// 引用类型
Integer integerVar = 123; // Integer
String stringVar = "Hello"; // String
Boolean booleanObjVar = true; // Boolean
byte[] byteArrayVar = new byte[]{1, 2, 3}; // byte[]
Date dateVar = new Date(); // Date
Pattern patternVar = Pattern.compile("abc"); // Pattern
Function<String, Integer> functionVar = String::length; // Function
Math mathVar = Math; // Math
Object objectVar = new Object(); // Object
System.out.println(byteVar); // 输出123
System.out.println(shortVar); // 输出12345
System.out.println(intVar); // 输出123456789
System.out.println(longVar); // 输出123456789012345
System.out.println(floatVar); // 输出1.23
System.out.println(doubleVar); // 输出1.23456789
System.out.println(charVar); // 输出A
System.out.println(booleanVar); // 输出true
System.out.println(integerVar.getClass().getName()); // 输出java.lang.Integer
System.out.println(stringVar.getClass().getName()); // 输出java.lang.String
System.out.println(booleanObjVar.getClass().getName()); // 输出java.lang.Boolean
System.out.println(byteArrayVar.getClass().getName()); // 输出[B
System.out.println(dateVar.getClass().getName()); // 输出java.util.Date
System.out.println(patternVar.getClass().getName()); // 输出java.util.regex.Pattern
System.out.println(functionVar.getClass().getName()); // 输出java.util.function.Function
System.out.println(mathVar.getClass().getName()); // 输出java.lang.Math
System.out.println(objectVar.getClass().getName()); // 输出java.lang.Object

注意:在Java中,数组使用大括号{}来初始化,而不是中括号[]。

数据结构

  • js
    JavaScript中的数据结构类型包括数组、对象、Map、Set等常用的数据结构类型如下:
// 数组
const arr = [1, 2, 3];
// Map
const map = new Map();
map.set('name', 'Tom');
map.set('age', 18);
// Set
const set = new Set();
set.add(1);
set.add(2);
  • Java
    Java中的数据结构类型包括数组、List、Map、Set、Queue、Stack
// 数组
int[] arr = {1, 2, 3};
// List
List<String> list = new ArrayList<>();
list.add("Tom");
list.add("Jerry");
// Map
Map<String, Integer> map = new HashMap<>();
map.put("Tom", 18);
map.put("Jerry", 20);
// Set
Set<Integer> set = new HashSet<>();
set.add(1);
set.add(2);
// Queue
Queue<String> queue = new LinkedList<>();
queue.offer("Tom");
queue.offer("Jerry");
// Stack
Stack<String> stack = new Stack<>();
stack.push("Tom");
stack.push("Jerry");

泛型

  • js
    在JavaScript中,没有泛型的概念,因此需要在代码中直接使用任意类型
  • ts
// 泛型变量T表示任意类型
function identity<T>(arg: T): T {
  return arg;
}
let output = identity<string>("Hello"); // output的类型为string
  • java
// 泛型变量T表示任意类型
public class Box<T> {
  private T t;
  public void set(T t) { this.t = t; }
  public T get() { return t; }
}
Box<Integer> box = new Box<Integer>(); // box存储的是Integer类型
box.set(10);
int num = box.get();

强制类型转换

  • js
    在JavaScript和TypeScript中,强制类型转换的方式和JavaScript原生方法一样,只是需要注意类型转换的方法名称和参数类型
let num1 = "10";
let num2 = Number(num1); // 将字符串转换为数字
let str1 = 123;
let str2 = String(str1); // 将数字转换为字符串
let bool1 = 1;
let bool2 = Boolean(bool1); // 将数字转换为布尔值
  • java
    在Java中,可以使用一些内置的函数来进行类型转换,如Integer.parseInt()和Integer.toString()
int num1 = Integer.parseInt("10"); // 将字符串转换为数字
String str1 = Integer.toString(123); // 将数字转换为字符串
boolean bool1 = (1 == 1); // 将数字转换为布尔值

Java中的强制类型转换和继承相关,可以将子类类型强制转换为父类类型,这种转换是安全的,反之则是不安全的。

class Animal {
    public void eat() {
        System.out.println("Animal is eating");
    }
}
class Dog extends Animal {
    public void bark() {
        System.out.println("Dog is barking");
    }
}
public class Main {
    public static void main(String[] args) {
        Animal animal1 = new Animal();
        Dog dog1 = new Dog();
        Animal animal2 = dog1; // 子类类型强制转换为父类类型
        Dog dog2 = (Dog) animal2; // 父类类型强制转换为子类类型
        animal1.eat(); // 输出Animal is eating
        dog1.eat(); // 输出Animal is eating,子类继承了父类的方法
        dog1.bark(); // 输出Dog is barking
        animal2.eat(); // 输出Animal is eating,子类类型被强制转换为了父类类型
        dog2.eat(); // 输出Animal is eating,父类类型被强制转换为了子类类型
        dog2.bark(); // 输出Dog is barking,子类类型被强制转换为了子类类型
    }
}

隐式、显式类型转换(自动装箱拆箱)

  • JS
    在JavaScript和TypeScript中,可以使用构造函数将基本数据类型转换为对象类型,这个过程称为装箱;可以使用valueOf()方法将对象类型转换为基本数据类型,这个过程称为拆箱。在进行数学计算时,JavaScript和TypeScript会自动进行装箱和拆箱。
let num1 = 10;
let num2 = new Number(num1); // 显示装箱
let num3 = num2.valueOf(); // 显示拆箱
let sum = num2 + 5; // 隐式装箱和拆箱
console.log(sum); // 输出15
  • Java

在Java中,基本数据类型不能直接转换为对象类型,但是Java提供了自动装箱和拆箱的功能。自动装箱是将基本数据类型自动转换为对应的包装类,自动拆箱是将包装类自动转换为对应的基本数据类型。

Integer num1 = 10; // 自动装箱
int num2 = num1; // 自动拆箱
int num3 = num1.intValue(); // 显式拆箱
int sum = num1 + 5; // 自动装箱和拆箱
System.out.println(sum); // 输出15

二、变量和常量

变量

JavaScript 中的变量(Variable)是一种用于存储数据值的标识符,可以通过 var、let、const 关键字来声明变量。在 JavaScript 中,变量可以存储任何类型的值,可以动态改变其值的类型。例如:

var name = "Tom"; // 使用 var 声明变量
let age = 18; // 使用 let 声明变量
const PI = 3.14; // 使用 const 声明常量
name = "Jerry"; // 动态改变变量的值

TypeScript 和 Java 中的变量与 JavaScript 中的变量类似,但是在类型系统上更加严格。在 TypeScript 和 Java 中,变量可以具有明确的类型,类型一旦确定就不能再改变。

TypeScript 中的变量:使用 let 或 const 关键字来声明变量,可以使用类型注解来指定变量的类型,也可以根据上下文自动推断变量的类型。例如:

let name: string = "Tom"; // 使用类型注解指定变量类型
let age = 18; // 自动推断变量类型为 number
const PI: number = 3.14; // 使用类型注解指定常量类型
name = "Jerry"; // 动态改变变量的值

Java 中的变量:使用基本数据类型或引用数据类型来声明变量,可以使用类型标识符来指定变量的类型。例如:

String name = "Tom"; // 使用类型标识符指定变量类型
int age = 18; // 使用基本数据类型来声明变量
final double PI = 3.14; // 使用 final 关键字声明常量
name = "Jerry"; // 动态改变变量的值

常量

  • js
    JavaScript中的常量使用const 关键字定义,一旦被定义,就不能再被重新赋值。常量的命名规则和变量相同,但通常使用全大写字母。
// 定义常量PI
const PI = 3.1415926;
// 以下代码会报错:Assignment to constant variable.
PI = 3;
  • Java
    Java中的常量使用final关键字定义,一旦被定义,就不能再被重新赋值。常量的命名规则和变量相同,但通常使用全大写字母。

关键字

  • JS
break      case     catch      class    const
continue   debugger default    delete   do
else       export   extends    false    finally
for        function if         import   in
instanceof new      null       return   super
switch     this     throw      true     try
typeof     var      void       while    with
  • Java
abstract    continue    for          new         switch
assert      default     if           package     synchronized
boolean     do          goto         private     this
break       double      implements   protected   throw
byte        else        import       public      throws
case        enum        instanceof  return      transient
catch       extends     int          short       try
char        final       interface    static      void
class       finally     long         strictfp    volatile
const       float       native       super       while

不用全记住,混个眼熟,IDE会帮你记住。
如果你在犹豫这个词是不是关键字,那就不要用。

字面量

JavaScript 中的字面量(Literal)是一种表示常量值的语法形式,包括字符串字面量、数值字面量、布尔字面量、对象字面量、数组字面量等。例如:

let name = "Tom"; // 字符串字面量
let age = 18; // 数值字面量
let isMale = true; // 布尔字面量
let person = { // 对象字面量
  name: "Tom",
  age: 18,
  isMale: true
};
let numbers = [1, 2, 3, 4, 5]; // 数组字面量

TypeScript 中的字面量包括字符串字面量、数值字面量、布尔字面量、对象字面量、数组字面量等,与 JavaScript 中的字面量相同。例如:

let name: string = "Tom"; // 字符串字面量
let age: number = 18; // 数值字面量
let isMale: boolean = true; // 布尔字面量
let person: { name: string, age: number, isMale: boolean } = { // 对象字面量
  name: "Tom",
  age: 18,
  isMale: true
};
let numbers: number[] = [1, 2, 3, 4, 5]; // 数组字面量

Java 中也有类似的字面量表示方式,称为字面值(Literal Value),包括字符串字面值、整数字面值、浮点数字面值、布尔字面值、字符字面值、null 字面值等。例如:

String name = "Tom"; // 字符串字面值
int age = 18; // 整数字面值
double height = 1.75; // 浮点数字面值
boolean isMale = true; // 布尔字面值
char gender = 'M'; // 字符字面值
Object obj = null; // null 字面值

三、运算符

  • js
    JavaScript中的运算符包括算术运算符、比较运算符、逻辑运算符、位运算符等。常用的运算符如下:

算术运算符

  • js
// 算术运算符
let a = 1, b = 2;
console.log(a + b); // 3
console.log(a - b); // -1
console.log(a * b); // 2
console.log(a / b); // 0.5
console.log(a % b); // 1
  • Java
// 算术运算符
int a = 1, b = 2;
System.out.println(a + b); // 3
System.out.println(a - b); // -1
System.out.println(a * b); // 2
System.out.println(a / b); // 0
System.out.println(a % b); // 1

比较运算符

  • js
// 比较运算符
console.log(a === b); // false
console.log(a !== b); // true
console.log(a > b); // false
console.log(a < b); // true
console.log(a >= b); // false
console.log(a <= b); // true
  • Java
// 比较运算符
System.out.println(a == b); // false
System.out.println(a != b); // true
System.out.println(a > b); // false
System.out.println(a < b); // true
System.out.println(a >= b); // false
System.out.println(a <= b); // true

逻辑运算符

  • js
// 逻辑运算符
let c = true, d = false;
console.log(c && d); // false
console.log(c || d); // true
console.log(!c); // false
  • Java
// 逻辑运算符
boolean c = true, d = false;
System.out.println(c && d); // false
System.out.println(c || d); // true
System.out.println(!c); // false

位运算符

  • js
// 位运算符
let e = 3, f = 5;
console.log(e & f); // 1
console.log(e | f); // 7
console.log(e ^ f); // 6
console.log(~e); // -4
console.log(f << 1); // 10
console.log(f >> 1); // 2
console.log(f >>> 1); // 2
  • Java
// 位运算符
int e = 3, f = 5;
System.out.println(e & f); // 1
System.out.println(e | f); // 7
System.out.println(e ^ f); // 6
System.out.println(~e); // -4
System.out.println(f << 1); // 10
System.out.println(f >> 1); // 2
System.out.println(f >>> 1); // 2

四、控制流程

条件语句

  • js
// 条件语句
let a = 1;
if (a === 1) {
  console.log("a is 1");
} else if (a === 2) {
  console.log("a is 2");
} else {
  console.log("a is neither 1 nor 2");
}
  • Java
// 条件语句
int a = 1;
if (a == 1) {
  System.out.println("a is 1");
} else if (a == 2) {
  System.out.println("a is 2");
} else {
  System.out.println("a is neither 1 nor 2");
}

循环语句

  • js
// for循环
for (let i = 0; i < 10; i++) {
  console.log(i);
}
// while循环
let j = 0;
while (j < 10) {
  console.log(j);
  j++;
}
// do-while循环
let k = 0;
do {
  console.log(k);
  k++;
} while (k < 10);
  • Java
// for循环
for (int i = 0; i < 10; i++) {
  System.out.println(i);
}
// while循环
int j = 0;
while (j < 10) {
  System.out.println(j);
  j++;
}
// do-while循环
int k = 0;
do {
  System.out.println(k);
  k++;
} while (k < 10);
// 增强for循环
int[] arr = {1, 2, 3, 4, 5};
for (int x : arr) {
  System.out.println(x);
}

跳转语句

  • js
// 跳转语句
let c = 0;
while (c < 10) {
  if (c === 5) {
    break;
  }
  console.log(c);
  c++;
}
let d = 0;
while (d < 10) {
  if (d === 5) {
    d++;
    continue;
  }
  console.log(d);
  d++;
}
  • Java
// 跳转语句
int c = 0;
while (c < 10) {
  if (c == 5) {
    break;
  }
  System.out.println(c);
  c++;
}
int d = 0;
while (d < 10) {
  if (d == 5) {
    d++;
    continue;
  }
  System.out.println(d);
  d++;
}

错误处理

  • js
try {
  // 可能会抛出异常的代码
} catch (error) {
  // 异常处理代码
  console.log(error.message);
} finally {
  // 最终执行的代码
}
  • Java
    catch块可以有多个,按照从上到下的顺序匹配异常类型,如果匹配成功,就执行对应的catch块中的代码。
try {
  // 可能会抛出异常的代码
} catch (NullPointerException e) {
  // 异常处理代码
  System.out.println(e.getMessage());
} catch (Exception e) {
  // 异常处理代码
  System.out.println(e.getMessage());
} finally {
  // 最终执行的代码
}

当发生NullPointerException异常时,只会执行第一个catch块中的代码,第二个catch块中的代码不会执行。如果发生其他类型的异常,第一个catch块不会执行,而是执行第二个catch块中的代码。
需要注意的是,在多个catch块中,应该按照从小到大的顺序排列异常类型,这样可以避免某个异常被多个catch块捕获导致代码逻辑混乱。

五、函数

定义

  • JS
// 函数声明
function myFunction(param1, param2) {
  // 函数体
  return result;
}
// 函数表达式
var myFunction = function(param1, param2) {
  // 函数体
  return result;
};
// 箭头函数
var myFunction = (param1, param2) => {
  // 函数体
  return result;
};
  • Java
public static ReturnType functionName(DataType param1, DataType param2) {
  // 函数体
  return result;
}

调用

  • JS
function sum(a, b) {
  return a + b;
}
let result = sum(1, 2);
console.log(result); // 3
  • Java
public class Main {
  public static void main(String[] args) {
    int result = sum(1, 2);
    System.out.println(result); // 3
  }
  public static int sum(int a, int b) {
    return a + b;
  }
}

重载

  • JS
    JavaScript中本身不支持函数重载,但是可以通过参数的类型、个数和返回值类型等特征来模拟函数重载。
function myFunction(param1) {
  if (typeof param1 === 'string') {
    // 函数体1
    return result1;
  } else if (typeof param1 === 'number') {
    // 函数体2
    return result2;
  } else {
    // 函数体3
    return result3;
  }
}

function myFunction2() {
   const param1 = arguments[0]
  if (typeof param1 === 'string') {
    // 函数体1
    return result1;
  } else if (typeof param1 === 'number') {
    // 函数体2
    return result2;
  } else {
    // 函数体3
    return result3;
  }
}

function myFunction3(...args) {
   const param1 = args[0]
  if (typeof param1 === 'string') {
    // 函数体1
    return result1;
  } else if (typeof param1 === 'number') {
    // 函数体2
    return result2;
  } else {
    // 函数体3
    return result3;
  }
}
  • TS
    TypeScript支持函数重载,可以通过定义多个函数签名来实现。
function myFunction(param1: DataType1): ReturnType1;
function myFunction(param1: DataType2, param2: DataType3): ReturnType2;
function myFunction(param1: DataType4, param2: DataType5, param3: DataType6): ReturnType3 {
  // 函数体
  return result;
}
  • Java
public ReturnType myFunction(DataType1 param1) {
  // 函数体1
  return result1;
}
public ReturnType myFunction(DataType2 param1, DataType3 param2) {
  // 函数体2
  return result2;
}
public ReturnType myFunction(DataType4 param1, DataType5 param2, DataType6 param3) {
  // 函数体3
  return result3;
}

递归

函数递归是指函数调用自身的过程,递归函数的性能较低,容易出现栈溢出等问题。

  • JS
function factorial(num) {
  if (num < 0) {
    return -1;
  } else if (num === 0 || num === 1) {
    return 1;
  } else {
    return num * factorial(num - 1);
  }
}
  • Java
public int factorial(int num) {
  if (num < 0) {
    return -1;
  } else if (num == 0 || num == 1) {
    return 1;
  } else {
    return num * factorial(num - 1);
  }
}

六、对象和数组

JavaScript 、TS、Java详细的对象和数组知识点?请各自用code方式输出,有哪些需要注意的

对象

  • JS
    JavaScript中的对象可以看作是一组键值对的集合,其中键是字符串或Symbol类型,值可以是任意类型的数据。
let person = {
  name: 'John',
  age: 30,
  hobbies: ['reading', 'swimming'],
  greet: function() {
    console.log('Hello, my name is ' + this.name);
  }
};
console.log(person.name); // John
console.log(person.hobbies[0]); // reading
person.greet(); // Hello, my name is John
  • Java
public class Person {
  private String name;
  private int age;
  private ArrayList<String> hobbies;
  public Person(String name, int age, ArrayList<String> hobbies) {
    this.name = name;
    this.age = age;
    this.hobbies = hobbies;
  }
  public String getName() {
    return name;
  }
  public int getAge() {
    return age;
  }
  public ArrayList<String> getHobbies() {
    return hobbies;
  }
  public void greet() {
    System.out.println("Hello, my name is " + name);
  }
}
public class Main {
  public static void main(String[] args) {
    ArrayList<String> hobbies = new ArrayList<String>();
    hobbies.add("reading");
    hobbies.add("swimming");
    Person person = new Person("John", 30, hobbies);
    System.out.println(person.getName()); // John
    System.out.println(person.getHobbies().get(0)); // reading
    person.greet(); // Hello, my name is John
  }
}

Java中的对象是基于类的,通过实例化类来创建对象。
对象的属性需要使用private修饰符来隐藏
通过公共的getter和setter方法来访问。Java中的对象方法需要使用public修饰符来公开访问

数组

  • JS
    JavaScript中的数组是一种有序的数据集合,可以存储任意类型的数据。
let arr = [1, 2, 3, 'four', true];
console.log(arr[0]); // 1
console.log(arr.length); // 5
arr.push('five');
console.log(arr); // [1, 2, 3, 'four', true, 'five']
arr.pop();
console.log(arr); // [1, 2, 3, 'four', true]
  • Java
public class Main {
  public static void main(String[] args) {
    String[] arr = {"one", "two", "three", "four"};
    System.out.println(arr[0]); // one
    System.out.println(arr.length); // 4
    String[] newArr = Arrays.copyOf(arr, arr.length + 1);
    newArr[4] = "five";
    System.out.println(Arrays.toString(newArr)); // [one, two, three, four, five]
  }
}

七、事件处理

  • JS
let btn = document.getElementById("myButton");
btn.addEventListener("click", function() {
  alert("Button clicked!");
});
  • Java
    事件一般用于GUI组件,Java可视化就算了吧…
public class Main {
  public static void main(String[] args) {
    JButton btn = new JButton("Click me!");
    btn.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        System.out.println("Button clicked!");
      }
    });
  }
}

八、面向对象

  • JS
// ES6 
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}
let person1 = new Person("John", 30);
person1.sayHello(); // Hello, my name is John and I'm 30 years old.


// 在ES5中,类没有类的概念,只有构造函数和原型对象的概念
function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function() {
  console.log("Hello, my name is " + this.name + " and I'm " + this.age + " years old.");
}
var person1 = new Person("John", 30);
person1.sayHello(); // Hello, my name is John and I'm 30 years old.
  • Java
public class Person {
  private String name;
  private int age;
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  public void sayHello() {
    System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
  }
}
public class Main {
  public static void main(String[] args) {
    Person person1 = new Person("John", 30);
    person1.sayHello(); // Hello, my name is John and I'm 30 years old.
  }
}

继承

  • JS
class Person {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
}
class Student extends Person {
  constructor(name, age, grade) {
    super(name, age);
    this.grade = grade;
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old. My grade is ${this.grade}.`);
  }
}
let student1 = new Student("John", 15, 9);
student1.sayHello(); // Hello, my name is John and I'm 15 years old. My grade is 9.


/// ES5 组合继承
function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.sayHello = function() {
  console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
}
function Student(name, age, grade) {
  Person.call(this, name, age);
  this.grade = grade;
}
Student.prototype = new Person(); // 组合继承
Student.prototype.constructor = Student; // 修改构造函数指向
let student1 = new Student("John", 15, 9);
student1.sayHello(); // Hello, my name is John and I'm 15 years old.
  • Java
public class Person {
  private String name;
  private int age;
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  public void sayHello() {
    System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
  }
}
public class Student extends Person {
  private int grade;
  public Student(String name, int age, int grade) {
    super(name, age);
    this.grade = grade;
  }
  public void sayHello() {
    System.out.println("Hello, my name is " + name + " and I'm " + age + " years old. My grade is " + grade + ".");
  }
}
public class Main {
  public static void main(String[] args) {
    Student student1 = new Student("John", 15, 9);
    student1.sayHello(); // Hello, my name is John and I'm 15 years old. My grade is 9.
  }
}

私有公有属性

  • JS
    在JavaScript中,没有正式的私有、公共、保护属性的概念,但可以通过约定来模拟这些属性。
class Person {
  constructor(name, age) {
    let _name = name; // 私有属性
    this.age = age; // 公共属性
    this.getName = function() { // 公共方法
      return _name;
    }
    this.setName = function(name) { // 公共方法
      _name = name;
    }
  }
  sayHello() {
    console.log(`Hello, my name is ${this.getName()} and I'm ${this.age} years old.`);
  }
}
let person1 = new Person("John", 30);
console.log(person1.age); // 30
console.log(person1.getName()); // John
person1.setName("Mike");
console.log(person1.getName()); // Mike
person1.sayHello(); // Hello, my name is Mike and I'm 30 years old.
  • Java
public class Person {
  private String name; // 私有属性
  protected int age; // 保护属性
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
  }
  public String getName() { // 公共方法
    return name;
  }
  public void setName(String name) { // 公共方法
    this.name = name;
  }
  public void sayHello() { // 公共方法
    System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
  }
}
public class Student extends Person {
  private int grade; // 私有属性
  public Student(String name, int age, int grade) {
    super(name, age);
    this.grade = grade;
  }
  public void sayHello() { // 公共方法
    System.out.println("Hello, my name is " + getName() + " and I'm " + age + " years old. My grade is " + grade + ".");
  }
}
public class Main {
  public static void main(String[] args) {
    Student student1 = new Student("John", 15, 9);
    System.out.println(student1.age); // 15
    student1.setName("Mike");
    System.out.println(student1.getName()); // Mike
    student1.sayHello(); // Hello, my name is Mike and I'm 15 years old. My grade is 9.
  }
}

私有属性可以通过private关键字来定义。
公共属性可以通过public关键字来定义。
保护属性可以通过protected关键字来定义。
在继承中,子类可以访问父类的保护属性。

静态属性

  • JS
    在JavaScript中,静态属性、方法是指与类本身相关的属性、方法,而不是与类的每个实例相关的属性、方法。
class Person {
  static count = 0; // 静态属性
  constructor(name, age) {
    this.name = name;
    this.age = age;
    Person.count++; // 静态属性的使用
  }
  sayHello() {
    console.log(`Hello, my name is ${this.name} and I'm ${this.age} years old.`);
  }
  static getCount() { // 静态方法
    console.log(`There are ${Person.count} people.`);
  }
}
let person1 = new Person("John", 30);
let person2 = new Person("Mike", 25);
person1.sayHello(); // Hello, my name is John and I'm 30 years old.
Person.getCount(); // There are 2 people.
  • Java
    静态方法中不能访问非静态属性、方法。
    Java静态属性、方法知识点:
    在Java中,静态属性、方法是指与类本身相关的属性、方法,而不是与类的每个实例相关的属性、方法。
public class Person {
  private String name;
  private int age;
  private static int count = 0; // 静态属性
  public Person(String name, int age) {
    this.name = name;
    this.age = age;
    count++; // 静态属性的使用
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public int getAge() {
    return age;
  }
  public void setAge(int age) {
    this.age = age;
  }
  public void sayHello() {
    System.out.println("Hello, my name is " + name + " and I'm " + age + " years old.");
  }
  public static void getCount() { // 静态方法
    System.out.println("There are " + count + " people.");
  }
}
public class Main {
  public static void main(String[] args) {
    Person person1 = new Person("John", 30);
    Person person2 = new Person("Mike", 25);
    person1.sayHello(); // Hello, my name is John and I'm 30 years old.
    Person.getCount(); // There are 2 people.
  }
}

九、其他

高阶函数

  • JS
  • Java

修饰器(注解)

  • JS
    -修饰器是一种特殊的函数,可以用来修改类的行为。修饰器函数接受三个参数:目标对象、属性名和属性描述符,可以通过修改这三个参数来改变类的行为。修饰器可以用来实现类的 mixin、属性的装饰、方法的装饰等功能。
  • Java
    注解是一种特殊的接口,可以用来为类、方法、变量等元素添加元数据。注解可以用来实现类的标记、参数的验证、代码生成等功能。注解可以通过反射机制来读取和处理。
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface Readonly {}
class Person {
    @Readonly
    String name = "John";
}
public class Main {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        Field field = Person.class.getDeclaredField("name");
        Readonly readonly = field.getAnnotation(Readonly.class);
        if(readonly != null) {
            field.setAccessible(true);
            field.set(person, "Mike");
        }
        System.out.println(person.name); // John
    }
}

私有属性

  • JS
  • Java

判空

let obj = {
  name: "John",
  age: null
};
let name = obj && obj.name || "Default Name";
let age = obj && obj.age || 0;
console.log(name); // John
console.log(age); // 0
console.log(obj?.getSex?.()); // undefined
// 声明注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLog {
    String value() default "";
}
// AOP
@Aspect
@Component
public class MyLogAspect {
    private static final Logger logger = LoggerFactory.getLogger(MyLogAspect.class);
    @Around("@annotation(myLog)")
    public Object logAround(ProceedingJoinPoint joinPoint, MyLog myLog) throws Throwable {
        String methodName = joinPoint.getSignature().getName();
        String logMsg = StringUtils.isNotBlank(myLog.value()) ? myLog.value() : methodName;
        logger.info("开始执行方法【{}】,日志消息:{}", methodName, logMsg);
        Object result = joinPoint.proceed();
        logger.info("方法【{}】执行完毕,返回值:{}", methodName, result);
        return result;
    }
}
// 使用
@MyLog("这是一个测试方法")
public String testMethod(String arg1, int arg2) {
    // 方法体
}

// 开始执行方法【testMethod】,日志消息:这是一个测试方法
// 方法【testMethod】执行完毕,返回值:xxx

数组内置遍历