Java

NOTE

intro

Grading

平时 70 期末 30 (PTA),斩杀

平时 = 出勤+HW(PTA)+小程+大程+(maybe)mid-exam(PTA)

开卷,可以带一本书,不能带笔记

ftp://java:java123456@10.15.62.53:211

建议用filezilla等客户端

笔记中还没弄清楚的内容::cactus:标记

something

Write once, compile, run anywhere!

1-Introduction

版本很多,学的基本是Java-6/7/8的基础知识

Java SE 8

Characteristics: simple, object-oriented, distributed, interpreted, robust, multithread, dynamic.

  • With Java, you write the program once, and compile the source program into a special type of object code, known as bytecode.
  • The bytecode can then run on any computer with a Java Virtual Machine.
  • Java Virtual Machine is a software that interprets Java bytecode.

  • Every Java program must have at least one class. (start with an uppercase letter) e.g. Welcome

  • Line 2 defines the main method. In order to run a class, the class must contain a method named main.
  • A statement represents an action or a sequence of actions.
public class Welcome {
    public static void main (String[] args) {
        System.out.println("Welcome to Java!");
    }
}

2-Elementary Programming

import java.util.Scanner;

public class ComputerAreaWithConsoleInput {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        
        System.out.print("Enter a radium:");
        double radium = input.nextDouble();
        
        System.out.println("The area... " + radius + " is " + area);
    }
}

Identifiers

consists of letters, digits, underscores (_), and dollar signs ($).

It cannot start with a digit. It cannot be a reserved word. It cannot be true, false, or null.

区分大小写:Int-:o: int-:x:

:question:Which one below is NOT a valid Java identifier?

A.Int :o:B.goto C.变量 D.$0

与c++区别

C/C++中int i = 10;是个定义,external int i;则是声明;在Java中不区分变量的声明与定义。

Java assigns no default value to a local variable inside a method. 对于方法的局部变量,java以编译错误来保证变量在使用前得到恰当初始化;而对于类中的局部变量,在声明类的对象时,每个基本类型的变量都会有一个初始值。

public class  Person{
    static int arr[] = new int[5];
    public static void main(String a[]) {
        System.out.println(arr[0]);
    }
}

:o:Prints 0

Named Constants

final datatype CONSTANTNAME = VALUE;

对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。

:anchor: final double PI = 3.14159;

Given a public member variable MAX_LENGTH as the int type is a constant of 100, the correct statement to define the variable is:

A. public int MAX_LENGTH = 100

B. final int MAX_LENGTH = 100

C. public const int MAX_LENGTH = 100

:o:D. public final int MAX_LENGTH = 100

final VS. const

final修饰变量:变量不可改变,但是值可以在运行时初始化final int i1 = (int)(Math.Random() * 10);/编译时初始化final i2 = 1;/构造函数中初始化final i3;

final修饰类对象,对象可以更改,但是变量不可赋成其他对象link: Java中Final修饰对象

final修饰方法:函数不可更改,即不能被重载,不是修饰返回值的

final修饰类:整个类不能被继承,类里所有方法相当于被加了final

Naming Conventions

  • Variables and method names: lowercase - radius
  • Class names: Capitalize the first letter of each word - ComputerArea
  • Constants: Uppercase - MAX_VALUE

Numerical Data Types

byte - 8 bits, short - 16 bits, int - 32 bits, long - 64 bits

Java中,整型的范围与运行Java代码的机器无关,没有sizeof()

:anchor:Calculations involving floating-point numbers are approximated because these numbers are not stored with complete accuracy.

:anchor:Integers are stored precisely.

Number Literals

byte b = 1000 :x: compilation error

An integer literal is assumed to be of the int type ($-2^{31}\sim 2^{31}-1$). To denote an integer literal of the long type, append it with the letter $L\text{ or } l$.

By default, a floating-point literal is treated as a double type value. Float - $F\text{ or }f$, double - $D\text{ or }d$.

System.out.println("1.0 / 3.0 is " + 1.0 / 3.0);
// 1.0 / 3.0 is 0.3333333333333333
System.out.println("1.0F / 3.0F is " + 1.0F / 3.0F);
// 1.0F / 3.0F is 0.33333334

正无穷大:Double.POSITIVE_INFINITY

负无穷大:Double.NEGATIVE_INFINITY

Not a Number:Double.NaN

Numeric Type Conversion

When performing a binary operation involving two operands of different types, Java automatically converts the operand based on the following rules:

如果一个操作数是xx,另一个就转化成xx,转化顺序double > float > long > int

Type Casting

类型转换(实线无信息丢失,虚线可能有精度损失):

隐式(implicit):double d = 3;

显式(explicit):int i = (int)3.9;

double x = 9.997, 求四舍五入后的整数

int nx = (int)Math.round(x);

为什么需要强制转化?返回结果是long类型int round(float x), long round(double x)

x1 op= x2 is implemented as x1 = (T)(x1 op x2), T is the type for $x1$.

int sum = 0;
sum += 4.5;
// sum becomes 4

Java不支持c++中的自动强制类型转换,如果需要,必须由程序显式进行强制类型转换

int ai; double ad = 1.2; ai = ad;

在C++编译器中最多出现警告,但是Java中不予通过。

3-Selections

boolean type and operators

one-way/two-way/… if statements

boolean even:

if (even == true) equivalent to if (even) :o:

if (even != 0) :x:(类型不同)

左结合右结合

i = 6; -i++ = ?

:o:“-”和“++”同一优先级,且为右结合,原式等价于-(i++)=-6

switch statements

switch(switch_expression) {
    case value1: statement(s)1;
        break;
    ...
    default: statement(s);
}

:anchor:The switch-expression must yield a value of char, byte, short, or int type and must always be enclosed in parentheses. (Java 1.7后支持了对string的判断,long:x:, boolean:x:)

(boolean-expression)?expression1:expression2: conditional expressions

System.out.println(
	(num%2==0) ? num+"is even" : num+"is odd");

Associativity: All binary operators except assignment operators are left-associative.

:o:a = b += c = 5 is equivalent to a = (b += (c = 5))

4-Mathematical Functions, Characters, and Strings

The Math Class

Class constants: PI, E

Class methods:

  • Trigonometric Methods: sin(double a), asin(double a)...

    :anchor:Math.sin(Math.PI / 2) returns 1.0

  • Exponent Methods: exp(double a), log, pow, sqrt

    :anchor:Math.pow(2, 3) return 8.0

  • Rounding Methods: double ceil(double x), double floor(double x) double rint(double x) x is rounded to nearest integer (equally close: returns even one) int round(float x), long round(double x) returns ()Math.floor(x+0.5)即四舍五入

  • min(a, b), max(a, b), abs(a), random()

    0 <= Math.random() < 1.0 :anchor:a + Math.random() * b => [a, a+b)

Character Data Type

The increment and decrement operators can also be used on char variables to get the next or preceding Unicode character.

:o:display character ‘b‘:

char ch = 'a';
System.out.println(++ch);

Unicode: 16 bits (2 bytes), preceded by \u, from \u0000 to \uFFFF(can represent 65535 + 1 characters)

Characters ASCII Unicode
‘0’ to ‘9’ 48 to 57 \u0030 to \u0039
‘A’ to ‘Z’ 65 to 90 \u0041 to \u005A
‘a’ to ‘z’ 97 to 122 \u0061 to \u007A

ASCII Character Set is a subset of the Unicode from \u0000 to \u007f

:warning:注意注释中的\u,会被理解成是Unicode

例如:// \u000A is a newline

// Look inside c:\users 会出现语法错误,因为\u后面不是四个十六进制数

String

  • isDigit(ch), isLowerCase(ch), toUpperCase(ch)

String is actually a predefined class in the Java library just like the System class and Scanner class. The String type is not a primitive type. It is known as a reference type.

  • charAt(0), length(), trim()
  • substring(beginIndex, endIndex), indexOf(ch)
class Main {
    public static void main(String[] args) {
        String s1 = "Zhejiang University";
        String s2 = s1.substring(0, 7);
        s2.toUpperCase();	// 没有改变s2
        System.out.println(S2+s1.substring(8));
    }
}

:o:Zhejian University

Input

Scanner input = new Scanner(System.in);
System.out.print("Enter a word:");
String s = input.next();
System.out.println("s is " + s);
  • next()从遇到第一个有效字符(非空格、换行符)开始扫描,遇到第一个分隔符或结束符(空格‘ ’或者换行符‘\n’)时结束。

  • nextLine()则是扫描剩下的所有字符串直到遇到回车为止。(可以从空格开始)

Scanner sc = new Scanner(System.in);
// input:aaa bbb ccc
str1 = sc.next();	// str1 = "aaa"
str2 = sc.nextline();	// str2 = " bbb ccc"

Formatting Output

System.out.printf(format, items);

占位符完整格式为:%[indexs$][标识][最小宽度][.精度]转换符

标识:

  • -:在最小宽度内左对齐,不可与0标识一起使用
  • 0:内容长度不足最小宽度时,在左边填充0
  • #:八进制(转换符o)前添0,十六进制(x)前添0x
  • +:结果总含+/-
  • ` (空格):正数前加空格,负数前加-`
  • ,:只用于十进制,每三位数字之间用,分隔
  • (:若结果为负数,用括号括住,且不显示符号
int num = -1000;
String str = String.format("%(,d", num);

:o:(1,000)

System.out.printf("%1$s %2$tB %2$te,%2$tY", "Due data:", new Date());
System.out.printf("%s %tB %<te, %<tY", "Due date:", new Date());

:o:Due date: February 9, 2015

5-Loops

while:

:x:use floating-point values for equality checking in a loop control (they are approximations for some values)

double item = 1; double sum = 0;
while(item != 0) { // No guarantee item will be 0
sum += item;
item -= 0.1;
}
System.out.println(sum);

do-while:

do {
    Statement(s);
} while (loop-continuation-condition);

for:

for (initial-action; loop-continuation-condition; action-after-each-iteration) {
Statement(s);
}

:anchor:correct, but rarely used:

for (int i= 1; i< 100; System.out.println(i++));
for (int i= 0, j = 0; (i+ j < 10); i++, j++) {
// Do something
}

break and continue

带标签,可以实现智能跳出语句块,更加灵活

label_break:
{
    if (condition) break label_break; // exit block
}
// jumps here
label_continue:
for(...) {
    if (condition) continue label_continue
    ...
    // jumps here (直接进入下一次for)
}

for-in:

float[] f = new float[10];
for(int i = 0; i < 10; i++)
    f[i] = rand.nextFloat();
for(float x : f)
    System.out.println(x);

:dart:range()方法:

Java 8中,可以利用它来建立流(后面详细讲stream)

(表示简单,考试经常出填空题等)

6-Methods

Method signature is the combination of the method name and the parameter list. (e.g. max(int num, in num2)) (同一个类里的方法构成重载时, method signature不一样)

When a method is invoked, you pass a value to the parameter. This value is referred to as actual parameter or argument. (调用方法时,传递参数的值,方法内值变,但是方法外值不变,内外共压栈两次)

value-returning method中,return语句应该覆盖全部情况

logically correct, but has a compilation error:

public static int sign(int n) {
    if (n > 0)
        return 1;
    else if (n == 0)
        return 0;
    else if (n < 0)	// else
        return -1;
}

类外方法调用:ClassName.methodName

重载 Overloading Methods:

public static int max(int num1, int num2);
public static double max(double num1, double num2);

(可以在同一个类里但signature得不一样,也可以在有继承关系的不同类里)

Ambiguous invocation is a compile error:

构成重载,但是有编译错误:错误来源是模糊匹配,如果是一个int,一个double则能正常编译运行。

public class AmbiguousOverloading {
    public static void main(String[] args) {
        System.out.println(max(1, 2));
    }
    public static double max(int num1, double num2) {
        ...
    }
    public static double max(double num1, int num2) {
        ...
    }
}

Scope of Local Variables:

starts from its declaration and continues to the end of the block that contains the variable. (cannot declare a local variable twice in nested blocks.)

Case Study:

  1. generate a random integer between 0 and 65535.

    (int)(Math.random() * (65535 + 1))

  2. generate a random integer between (int)'a' and (int)'z'. (The Unicode for 'a' is (int)'a')

    (int)((int)'a' + Math.random() * ((int)'z' - (int)'a' + 1)) The char operand is cast into a number if the other operand is a number or a character. So, the preceding expression can be simplified as follows: 'a' + Math.random() * ('z' - 'a' + 1)

  3. generate a random lowercase letter. (char)('a' + Math.random() * ('z' - 'a' + 1))

Developing programs:

  • Design: stepwise refinement (divide and conquer)
  • Implementation: top-down, bottom-up

7-Single-Dimensional Arrays

Java中没有指针的概念,只有reference

  • 声明(declare)datatype[] arrayRefVar; datatype arrayRefVar[]; is allowed, but not preferred.

  • 创建(create)arrayRefVar = new datatype[arraySize];

  • in one step: datatype[] arrayRefVar = new datatype[arraySize];

  • 创建的数组长度固定不可变:arrayRefVar.length(注意和Str.length()区别)

  • default value: 0(numeric), \u0000(char), false(boolean)

  • Declaring, creating, initializing using the Shorthand Notation: double[] myList = {1.9, 2.4, 3.6, 5.7};

    :x:syntax error: 没有创建数组就进行初始化

    double[] myList;
    myList = {1.9, 2.4, 3.6, 5.7};
    

Java数组 VS. C++数组

  • Java数组分配在堆上。C++中,int a[100]分配在栈上,int* a = new int[100]分配在堆上。
  • Java中,int a[100];:x: (syntax error)
  • Java中的[]运算符被预定义为检查数组边界,而且没有指针运算,就不能通过a+1得到下一个元素。

  • 命令行参数,带有String[] args,在Java中args不存储程序名,args[0]就是第一个参数。

Processing Arrays

Initializing arrays with input values:

java.util.Scanner input = new java.util.Scanner(System.in);
System.out.print("Enter " + myList.length + " values: ");
for(int i = 0; i < myList.length; i++)
	myList[i] = input.nextDouble();

Coping Arrays:

浅拷贝 list2 = list1;(实际上二者指向一个内容,一改俱改)

深拷贝 using a loop

System.arraycopy Utility:

arraycopy(sourceArray, src_pos, targetArray, tar_pos, length);

Arrays.copyOf:

int[] copiedLuckyNumbers = Arrays.copyOf(luckNumbers,luckyNumbers.length);

第2个参数是新数组的长度,这个方法通常用来增加数组的大小

如果数组元素是数值型,则多余的元素被赋值为0;若是布尔型,则赋值为false。如果长度小于原始数组长度,则只拷贝前面的元素。

:cactus: 区别两个函数 Arrays.copyOf和System.arraycopy

Passing Arrays to Methods:

public static void printArray(int[] array){...}
// invoke the method
// example 1
int[] list = {3, 2, 4, 1, 8};
printArray(list);
// example 2 -- Anonymous array 匿名数组
printArray(new int[]{3, 2, 4, 1, 8});

:o:There are important differences between passing a value of variables of primitive data types and passing arrays.

:anchor:For a parameter of a primitive type value, the actual value is passed. Changing the value of the local parameter inside the method does not affect the value of the variable outside the method.

:anchor:For a parameter of an array type, the value of the parameter contains a reference to an array; this reference is passed to the method. Any changes to the array that occur inside the method body will affect the original array that was passed as the argument.

Linear Search, Binary Search

Selection Sort

:o:Java provides several overloaded sort methods for sorting an array of int, double, char, short, long, and float in the java.util.Arraysclass.

double[] numbers = {5.4, 3.2, 5.9, 1.0};
java.util.Arrays.sort(numbers);

8-Multidimensional Arrays

dataType[][] refVar;

refVar = new dataType[10][10];

=> dataType[][] = new dataType[10][10];

int[][] array = {
    {1, 2, 3},
    {4, 5, 6},	// array.length = 4
    {7, 8, 9},	// array[0].length = 3
    {10, 11, 12}
};
// array[4].length: ArrayIndexOutOfBoundsException

Each row in a two-dimensional array is itself an array. So, the rows can have different lengths.

创建的过程也可以分开两步

(为了网页显示不得不用了图片,现在这个架构还是太敏感肌了一点,迟早得换)

9-Objects and Classes

java,完全面向对象,没有全局变量/方法

Constructor (do not have a return type, using new operator, default ctor只有在没有显式构造函数的时候—只定义显式有参的构造函数调用无参会编译错误)

Circle myCircle = new Circle(5.0);
// Circle myCircle: declare --> stack
// new Circle(5.0): create --> heap
// =: assign object reference to myCircle

static函数调用:ClassName.methodName(arg)

If a data field of a reference type does not reference any object, the data field holds a special literal value, null. (reference type 如 String 初始化就是null)

public class InitialValue {
    int i = 999;
}
// 默认初始化之后才执行指定初始化,因此i先0后999

c1 = c2后,c1指向 same object referenced by c2,这时原来指向的对象是garbage,会被JVM自动回收。

对不用的对象可以显式赋值null设置回收(不是立马回收,而是有检查机制确定有空闲了回收)。如果ref仍有指向,内容不会被回收,就造成了内存泄露

The Date Class

java.util.Date date = new java.util.Date();
System.out.println(date.toString());
// (like) Sun Mar 09 13:50:19 EST 2003

The Random Class

Math.random()做区分;相同种子相同值

静态方法只能访问静态变量,调用静态方法,不能访问/调用实例变量/方法(实例方法都能访问/调用)

private Ctor

  1. 不能创建类的实例,类只能被静态访问
  2. 能创建类的实例,但只能被类的静态方法调用(常见:单例模式):cactus:java 9-63
  3. 只能被其他构造函数调用,用于减少重复代码:cactus:

link

值传递 / 引用传递(还是按值传递的):cactus:

link

Immutable Objects and Classes不可变对象/类:

一旦创建,内容就不可变。

不可变对象:

比较简单,只有被创建时的那一种状态,本质上是线程安全的。

不可变类:(不可被扩展 <= final

mark all data fields private and provide no mutator methods (会修改对象状态的方法) and no accessor methods that would return a reference to a mutable data field object.

缺点是对于每一个不同的值都需要创建一个新的单独的对象

:anchor:String, 基本类型的包装类(如Integer, Long),LocalDate

String的可变配套类为StringBuilder

A class with all private data fields and without mutators is not necessarily immutable.

public class Stu {
    private BirthDate birth;
    public BirthDate getBirth() {
        return birth;
    }
    ...
}
public class Test {
    ...
    BirthDate date = stu.getBirth();
    date.setYear(2010);
}

NOTE:必要时进行保护性拷贝(如下)

public BirthDate getBirth() {
    return new BirthDate(...);
}

:cactus:公有的静态final数组域可能导致安全漏洞

Java反编译工具:jad xxx.class

:cactus: 为了确保不可变性,类不允许自身被子类化。除了final外,还有一种方式:让类的所有构造器都变为私有/包级私有的,并添加公共的静态工厂来代替公有的构造器。

public class Complex{
	private final double re;
	private final double im;
	privateComplex(double re, double im){
		this.re = re;
		this.im = im;
	}
	public static Complex valueOf(double re, double im){
	return new Complex(re,im);
	}
}

=> Constant Pool 常量池技术

Integer a = new Integer(3);
Integer b = 3;
 // 反汇编:Integer b = Integer.valueOf(3);
int c = 3;
System.out.println(a == b); // false
System.out.println(a == c); // true

对象构建TIPS

  1. 遇到多个构造器参数时可以考虑用构建器Builder:

(重叠构造器/无参构建器然后setter,前者难以阅读且颠倒参数位置会有错误但不报错,后者难以保证一致性且不能做成不可变类)

  1. 也可以考虑用静态工厂方法代替构造器:cactus:(9-107)

  2. 单例对象构建:通常对于哪些本质上唯一的对象,如文件系统、窗口管理器等

枚举:cactus:

Enum提供了序列化方法,而且绝对防止多次实例化。

Package包:

package语句作为java源文件第一条语句(省略则指定为无名包)

java.time.LocalDate today = java.time.LocalDate.now();
// OR
import java.time.*;
LocalDate today = LocalDate.now();
// OR
import java.time.LocalDate;

命名冲突时,要明确包的名字

import java.util.*;
import java.sql.*;
Date today; // compile error
=>
import java.util.Date;
// OR
java.util.Date today = new java.util.Date();

import不会递归,只会引入当前package下的直接类(嵌套引入:x:import java.util.*.*

默认import java.lang.*;,没看到package类别时编译器会自动找

import还可以导入静态方法和静态域

import static java.lang.System.*;
outprintln("Hello");
exit(0);

编译器在编译源文件时不检查目录结构,因此放错文件夹能编译通过,但是执行时会报错(把.class放在正确文件夹下就能执行)

JAR:

Java Archive. A group of Java classes and supporting files combined into a single file compressed with ZIP format, and given .JAR extension.

(ads: compressed, quicker download; just one file, less mess; can be executable)

jar -cvf MyProgram.jar *.class *.gif *.jpg #create
java -jar MyProgram.jar #run

Most OSes can run JARs directly by double-clicking them.

主清单属性 manifest

> jar -cvfe hhh.jar hello hello.class
> java -jar hhh.jar
Hello, World!

一些例子:

JAVA> jar -cvfe test/hhh.jar test.hh test/hh.class
JAVA> java -jar test/hhh.jar
Hello, world!
JAVA> jar -cvfe hh.jar test.hh test/hh.class
JAVA> java -jar hh.jar
Hello, world!
JAVA> jar -cvmf test/manifestFile.mt test/main.jar test/*.class
JAVA> java -jar test/main.jar
10

You can embed external resources inside your JAR, but code for opening files will look outside your JAR, not inside it.

Luckily, every class has an associated .class object with these methods:

public URL getResource(String filename)
public InputStream getResourceAsStream(String name)

If a class named Example wants to load resources from within a JAR, its code to do so should be the following:

Scanner in = new Scanner(Example.class.getResourceAsStream("/date.txt"));
ImageIcon icon = new ImageIcon(Example.class.getResource("/pony.png"));
Toolkit.getDefaultToolkit().getImage(Example.class.getResource("/images/cat.jpg"));
// Toolkit read from URLs.

10-Thinking in Objects

面向对象=>抽象和封装 Abstraction and Encapsulation

11-Inheritance and Polymorphism

Inheritance继承

class A extends B {}

子类不会继承父类的构造函数,利用super在子类构造函数中调用父类构造函数(没有显式使用super时,默认调用无参的构造函数)

public A() { }
<==>
public A() {
    super();
}
public A(double d) {...}
<==>
public A(double d) {
    super();
    ...
}
public class Apple extends Fruit { }
class Fruit {
    public Fruit (String name) {
        System.out.println("xxx");
    }
}

:x:error: 应该调用Fruit的无参构造函数,但是没定义

super调用父类方法:

public void printCircle() {
    System.out.println("The circle is created" + super.getDataCreated() + "and the radius is " + radius);
}

method override方法重写:

要能被子类访问到(private不行,此时子类中可以重新定义一个同名的方法,但这两个方法是无关的);不能是static方法(子类中若有,则二者也无关,不是override);不能是final方法

使用override注解(O是大写),可以防止非法错误(编译器会报错)

@Override public boolean equals(Bigram b) {
    return b.first == first && b.second == second;
}

overload方法的选择是静态的,override方法的选择是动态的

public class CollectionClassifier {
    public static String classify(Set<?> s) {
        return "Set";
    }
    public static String classify(List<?> l) {
        return "List";
    }
    public static String classify(Collection<?> c) {
        return "Unknown Collection";
    }
    public static void main(String[] args) {
        Collection<?>[] collections = {new HashSet<String>(), new ArrayList<Integer>(), new HashMap<Integer, String>().values()};
        for (Collection<?> c : collections) {
            System.out.println(classify(c));
        }
    }
}
// output
Unknown Collection
Unknown Collection
Unknown Collection

:cactus:overload静态匹配参数

Java中所有的类都是从Objectjava.lang.Object)中继承的:

public class Circle {}
<==>
public class Circle extends Object {}

:anchor:toString()

默认函数返回class_name@a_number_representing_this_object

常常要自己重写来实现tostring()

Loan loan = new Loan();
System.out.println(loan.toString());
// output
Loan@15037e5

Polymorphism多态

多态性:在多态中,父类引用可以指向子类对象。但是,这种多态性主要体现在方法的动态绑定上,而不是成员变量的访问。

成员变量的访问:当我们通过父类引用访问成员变量时,访问的是父类中定义的成员变量,而不是子类中的。

a variable of a supertype can refer to a subtype object.

dynamic binding动态绑定:具体实现在Java虚拟机跑程序时决定

public class PolymorphismDemo {
    public static void main(String[] args) {
        m(new GraduateStudent());
        m(new Student());
        m(new Person());
        m(new Object());
    }
    public static void m(Object x) {
        System.out.println(x.toString());
    }
}

class GraduateStudent extends Student {}
class Student extends Person {
    public String toString() {
        return "Student";
    }
}
class Person extends Object {
    public String toString() {
        return "Person";
    }
}

// output
Student
Student
Person
java.lang.Object@15db9742

method matching (according to parameter type,number of parameters, and order of the parameter) : compilation time

dynamically binding: runtime

这其中有隐式转换:

m(new Student());
<= implicit casting =>
Object o = new Student();
m(o);

:x:Student b = o; compile error ==>:o:Student b = (Student o) but this type of casting may not always succeed.

:o:Object o = new Student()

:anchor:instanceof: test whether an object is an instance of a class

Object myObject = new Circle();
...
if (myObject instanceof Circle) {
    System.out.println("xxx")
}

类型转换失败时,c++生成null对象,而java是抛出异常:

Manager* boss = dynamic_cast<Manager*>(staff); // c++
if (boss != NULL) ...
if (staff instanceof Manager) {
    Manager boss = (Manager)staff;
}

在父类构造函数中调用被重写的方法,可能有意想不到的结果:

class Base {
    public int a = 1;
    public Base() {
        test();
    }
    public void test() {
        System.out println("Base.test(): " + a);
    }
}
public class Child extends Base {
    public int a = 123;
    public Child() {}
    public void test() {
        System.out.println("Child.test(): " + a);
    }
    public static void main(String[] args) {
        Child c = new Child();
        c.test();
    }
}
// output
Child.test(): 0
Child.test(): 123

初始化对象的存储空间为零或null值->调用父类Ctor->按顺序调用类成员变量和实例成员变量的初始化表达式->调用本身Ctor

对于上述代码,如果加入Base b = c;,则b.a == 1; c.a == 123

对于static方法,没有动态绑定(可继承但是没有重写),传入是什么类型就调用对应类型的函数

:anchor:equals

默认实现为return this == obj;,即判断whether two objects have the same references,因此经常需要自己重写

String str1 = new String("abc");
String str2 = new String("abc");
String str3 = "abc";
String str4 = "abc";
System.out.println(str1.equals(str2)); // 1
System.out.println(str1 == str2); // 0
System.out.println(str3.equals(str4)); // 1
System.out.println(str3 == str4); // 1,常量池

protected:

A protected data or a protected method in a public class can be accessed by any class in the same package or its subclasses, even if the subclasses are in a different package.

Modifier same class same package subclass different package
public :o: :o: :o: :o:
protected :o: :o: :o: :heavy_multiplication_x:
default :o: :o: :heavy_multiplication_x: :heavy_multiplication_x:
private :o: :heavy_multiplication_x: :heavy_multiplication_x: :heavy_multiplication_x:

Subclass cannot weaken the accessibility:

:o:superclassprotected —> subclasspublic

复习final: class - cannot be extended, variable - constant, method - cannot be overriden

继承实现过程:

public class Base {
    public static int s;
    private int a;
    static {
        System.out.println("B static, s: " + s);
        s = 1;
    }
    {
        System.out.println("B instance, a: " + a);
        a = 2;
    }
    public Base() {
        System.out.println("B ctor, a: " + a);
        a = 3;
    }
    public void step() {
        System.out.println("B step, s/a: "+s+","+a);
    }
    public void action() {
        System.out.println("start action");
        step();
        System.out.println("end action");
    }
}
public class Child extends Base {
    public static int s;
    private int a;
    static {
        System.out.println("C static, s: " + s);
        s = 100;
    }
    {
        System.out.println("C instance, a: " + a);
        a = 200;
    }
    public Child() {
        System.out.println("C ctor, a: " + a);
        a = 300;
    }
    public void step() {
        System.out.println("C step, s/a: "+s+","+a);
    }
    public static void main(String[] args) {
        System.out.println("-----new Child()-----");
        Child c = new Child();
        System.out.println("-----c.action()-----");
        c.action();
        Base b = c;
        System.out.println("-----b.action()-----");
        b.action();
        System.out.println("b.s: "+b.s+", c.s: "+c.s);
    }
}
// output
B static, s: 0 // 类加载过程
C static, s: 0
-----new Child()----- // 对象创建过程
B instance, a: 0
B ctor, a: 2
C instance, a: 0
C ctor, a: 200
-----c.action()-----
start action
C step, s/a: 100,300
end action
-----b.action()----- // 动态绑定
start action
C step, s/a: 100,300
end action
b.s: 1, c.s: 100 // 静态变量访问

父类不能随意增加公开方法,因为父类增加就是给所有子类增加,而子类可能要重写该方法才能保证方法的正确性。

设计模式之装饰器模式

interface(后面学)没有实现函数,就是一个接口

// 前提
public interface FriedChicken {
    void makeFriedChicken();
}
public class KFC implements FriedChicken {
    @override
    public void makeFriedChicken() {
        System.out.println("made in KFC");
    }
}
public class McDonald implements FriedChicken {};
// 装饰类
public class Decorator implements FriedChicken {
    private FriedChicken friedChicken;
    
    public Decorator(FriedChicken friedChicken) {
        this.friedChicken = friedChicken;
    }
    @override
    public void makeFriedChicken() {
        friedChicken.makeFriedChicken();
        System.out.println("check");
    }
}

Nested Class 嵌套类

public class Outer
{
    private class Inner {}
}

Inner class只是Java编译器的概念,JVM则不知道内部类这回事(每个内部类会编译为一个独立的类,生成独立class文件)

:anchor:static inner class(静态内部类):

可以访问外部类的static变量和方法(哪怕是private也可以访问),但不能访问成员变量和方法。外部类可以直接使用内部类(public则可以被外部使用Outer.StaticInner si = ...

实现机制:自动生成一个新的类Outer$StaticInner,如果使用了外部类的private变量,则在外部类自动生成一个Outer.access$0(),其用法类似于Outer.getVariable

:anchor:inner class(成员内部类):

内部类可以直接使用外部类的变量和方法(private也可以)。

外部类(或里面的另一个内部类)可以使用内部类(包括private):

Inner inner = new Inner();
inner.display();
System.out.println("Inner y:" + inner.y); // ok
System.out.println("Inner y:" + y); // ERROR!

外部使用则需要和一个外部类对象相连:

Outer outer = new Outer();
Inner inner = outer.new Inner();

实现机制:自动生成类Outer$Inner且有一个指向外部类对象的ref,如果使用了private变量/方法,则在外部类自动生成access$0(Outer outer)

当内部类调用函数时:如果内部类有,则调用内部的;否则在外部类找;如果内外都有但是想用外部类的,Outer.this.methodName

Nesting Inner Classes嵌套内部类:用的不多,一般在类里做辅助

A aObj = new A();
A.B bObj = aObj.new B();
A.B.C cObj = bObj.new C();

:anchor:local class(方法内部类):

只能在定义的方法内使用

static方法,内部类只能访问外部类的静态变量/方法;instance方法,内部类可以访问外部类的变量和方法。

内部类可以访问方法的参数和局部变量,必须是final。(方法的局部变量位于栈上,只存在于方法的生命期内,当方法结束,其栈结构被删除。但是方法结束后,方法内部类可能仍存在于堆中,比如引用被传递到其他代码并存在一个成员变量中。)

实现机制:自动生成类Outer$Inner,且包含了外部类的实例和使用的方法中参数/局部变量的实例。访问private的机制则和内部类一样。

方法内部类中修改外部变量:

public class Outer {
    public void test() {
        final String[] str = new String[]{"Hello", "World"};
        class Inner {
            public void innerMethod() {
                str[0] = "Goodbye";
            }
        }
        Inner inner = new Inner();
        inner.innerMethod();
        System.out.println(str[0]);
    }
    public static void main(String[] args) {
        Outer outer = new Outer();
        outer.test();
    }
}

:anchor:Anonymous class(匿名内部类):

匿名内部类没有单独的类定义,它在创建对象的同时定义类且只能使用一次

TODO…

126 蓝色构造匿名类,后面很常见(new的时候同时构建定义了)

12-Abstract Classes and Interfaces

Abstract Class

类里面有abstract方法时,如果new了对象,则调用该方法就会失败,因此这个类必须是抽象类

(UML写法:abstract斜体public+protected#private-static_

  1. 抽象类不能被包含在非抽象类中
  2. 可以有构造函数
  3. 可以没有抽象方法(被当作基类用来定义新的子类)
  4. 具体类的子类可以是抽象类(具体类:Object

Interfaces

只有常量和抽象方法(Java 7之前的说法,考试一般按这个来)

(Java 8中,允许定义静态方法和默认方法,但必须是public的;Java 9中去掉了该限制)

public interface InterfaceName {
    constant declarations;
    abstract method signatures;
}

All data fields are public final static and all methods are public abstract in an interface. For this reason, these modifiers can be omitted, as shown below:

public interface T1 {
    public static final int K = 1;
    public abstract void p();
}
<=>
public interface T1 {
    int K = 1;
    void p();
}

:anchor: Comparable Interface

package java.lang;
public interface Comparable<E> {
    public int compareTo(E o);
}

Integer等numeric wrapper类和Character类都implement了Comparable interface,因此compareTo方法在这些类内实现。

java.util.Arrays.sort(array)方法要求数组内元素instanceof Comparable

一个类可以实现多个接口:

interface Interface1{}
interface Interface2{}
public class Test implements Interface1, Interface2 {}

接口可以继承:

interface IB1{}
interface IB2{}
interface IC extends IB1, IB2{}

Marker Interface: an empty interface,不含任何内容,只是标记意图

package java.lang;
public interface Cloneable{}

实现Cloneable的类被标记为可克隆的,利用定义在Object类里的clone()实现

实现深拷贝的时候指向不同对象,但是内容一样(==是false,equals是true)

Interfaces vs. Abstract Classes

接口类里只有constants的数据(public static final);抽象类里可以有各种类型的数据

接口类没有构造函数,方法没有实现;抽象类里的可以有实现

(如果一个类实现了两个冲突的接口,比如同一个常数有不同的值,编译器会检测出来)

:anchor: a staff member is a person => using class

:anchor: all strings are comparable (certain property) => using interface

Designing a Class

一个类描述了一个实体,应该避免一个类有太多职责,同时对equals等方法进行重写。

10个面向对象的设计原则(不考):

消除重复、封装变化(封装认为未来会发生变化的代码)、开闭原则(对扩展开放、对修改关闭)、单一职责、依赖注入或倒置原则(细节依赖抽象)、合成复用(尽量用对象组合而不是继承)、里氏代换原则(子类能够替换基类=>派生类或子类必须增强功能)、接口隔离、针对接口编程而不是针对实现、委托原则

13-Exception Handling and Text IO

Exception

Error一般由JVM抛出,且难以修复;Exception由程序和环境造成,一般可以被程序处理。

unchecked exceptions: runtime exception, error and their subclasses (只通知不处理)

method1() {
    try {
        invoke method2;
    }
    catch (Exception ex) { // catching exceptions
        process exception;
    }
}

method2() throws Exception { // declaring exceptions: throws
    if (an error occurs) {
        throw new Exception(); // throwing exception: throw
    }
}

对于checked exception,必须要处理。可以用try-catch直接处理,也可以throws抛出让调用函数处理。

finally语句一定会执行(无论程序以什么方式离开try块,比如try/catch中抛出异常/执行return、break、continue):

try {
    statements;
}
catch (TheException ex) {
    handling ex;
}
finally {
    finalStatements;
}

不会执行next statement,因为会抛出异常(handling ex -> finalStatement -> throw ex)

try {
    statement;
}
catch (Exception ex) {
    handling ex;
    throw ex; // rethrowing exceptions
}
finally {
    finalStatement;
}
next statement;

注意:

  1. 捕获了checked异常后要处理
  2. 一般不捕获unchecked异常
  3. 不要一次捕获所有的异常(下方代码)
  4. 使用finally块释放资源
  5. 不能在finally块抛出异常(其他异常信息丢失,外部捕捉到的是finally中的异常信息)
  6. 抛出自定义异常时带上原始异常信息throw new MyException(e.getMessage);
  7. 打印异常信息时带上异常栈堆e.printStackTrace();
  8. 不要用“异常机制+返回值”e.getErrcode == -1来进行异常处理
  9. 不要让try块过于庞大
  10. 守护线程(需要长时间运行的线程)需要catch runtime exception
try {
    method1();
    method2();
}
catch (ExceptionA e) {...}
catch (ExceptionB e) {...}

发生异常后,JVM会由上至下检测catch语句是否与发生的异常匹配,若匹配则不执行其他catch语句块。因此捕获子类异常的catch语句要放在父类前。

如果捕获子类异常的catch语句被放在父类catch语句后面,编译器会报错。(e.g. Unreachable catch block for B. It is already handled by the catch block for A.)

Assertions

为程序断言一个假设,判断程序是否为逻辑正确的:

assert assertion
// OR
assert assertion: detailMsg

AssertionError有一个无参Ctor和对应int, long, float, double, boolean, char, Object的单参数Ctor;它是Error的子类,当断言是false,程序在控制台打印信息并退出。

assert i == 10;
assert sum > 10 && sum < 5 * 10 : "sum is"  + sum;

1.4以前需要特殊编译javac -source 1.4 AssertionDemo.java,现在不需要

运行时默认没有,不能够来替代检查参数的,开启需要java -enableassertions Demo,或-ea;也可以选择性控制,如java -ea:package1 -da:Class1 Demo

:anchor: 一个好的应用是放在switch语句中的default里:

switch (month) {
    case 1: ...; break;
    ...
        default: assert false : "Invalid month: " + month;
}

I/O

封装类:File,filename是string,实现了对name和path的封装,但是没有实现I/O

两种方式去存数据:text format(人类可读,一系列characters);binary format(用bytes表示)

Java Stream相关类用来处理字节流(8bit),而非字符流(16bit)

:anchor: java.io.PrintWriter

public class WriteData {
    public static void main(String[] args) throws Exception {
        java.io.File file = new java.io.File("source.txt");
        if (file.exists()) {
            System.out.println("File already exists");
            System.exit(0);
        }
        java.io.PrintWriter output = new java.io.PrintWriter(file);
        output.print("John T Smith");
        output.Close();
    }
}

可以指定字符集,否则使用运行该程序的机器的默认编码:

PrintWriter out = new PrintWriter("myfile.txt", "UTF-8");

try-with-resources语法自动关闭文件:

try (declare and create resource) { // line 8 at last java block
    Use the resource to process the file; // line 9
}

:anchor: Scanner

Scanner in = new Scanner(Paths.get("myfile.txt"), "UTF-8");
Scanner in = new Scanner(new File("myfile.txt"), "UTF-8");

:anchor: Replacing Text

java ReplaceText sourceFile targetFile oldStr newStr
java ReplaceText Format.java t.txt StringBuilder StringBuffer

替换Format.java中所有StringBuilder为StringBuffer,保存在t.txt中

URL class:

URL url = new URL("www.google.com/index.html");
Scanner input = new Scanner(url.openStream());
...

14-Binary I/O

byte没有编码解码

25 b

不是所有对象都能够写到文件里:47

中文的这些考试也不太会考,不太重要

-75用的不多,过一下而已

15-Recursion

注意有时候一个问题很容易用递归来求解,但是一直需要压栈,栈可能不太够。

例如,用递归判断回文,会创建许多String,浪费资源=>使用helper method(s.charAt(low)==s.charAt(high)类似利用指针来判断)

其他例子:directory size,tower of Hanoi,GCD,Sierpinski Triangle

Tail Recursion 尾递归:最后一个递归调用结束后,方法也结束=>无需将中间的调用存在栈中,编译器会优化尾递归来减少栈空间。

return n * factorial(n - 1);
return factorial(n - 1, n * res); // tail recursion

16-Generics

泛型对类型进行参数化 parameterize types,让编译器在编译时就知道是否出错(实际运行的时候泛型信息已经被擦除,变成了具体的类或是其他内容)

package java.lang;
public interface Comparable {
    public int compareTo(Object o);
}
// runtime error
Comparable e = new Date();
System.out.println(e.compareTo("red")); // Date和String类型不匹配
package java.lang;
public interface Comparable<T> {
    public int compareTo(T o)
}
// compile error
Comparable<Date> e = new Date();
System.out.println(e.compareTo("red"));

可以有多个类型的参数:public class Pair<U, V> {}

泛型方法 Generic Method:

public static <E> void print(E[] list) {
    for (int i = 0; i < list.length; i++)
        System.out.print(list[i] + " ");
    System.out.println();
}
// call
GenericMethodDemo.<String>print(strings);

TODO

19父类一样所以可以

31 b

运行的时候没有E

-45

约束

17-Java Collections Framework

The Java Collections Framework supports three types of collections, named sets, lists,and maps.

4 6

map和set/list不一样,后者都是collection的子接口,但是map不是

set不能有重复元素(不是ref判断,而是equals判断)

duplicate

72 collections,有s,是class

18-JavaBeans, Swing Tutorial, GUI

整个GUI的基础知识,编程需要,考试考的不多

JavaBean:可序列化,public,构造函数无参的java类

所有GUI类是一个JavaBean组件

:anchor: get, is, set

Java event delegation model (事件代理模型):Bean之间可以交流、传递信息

很多内容,比如:Containers, Layout Managers, Borders

container容器是包含、展示、管理组件的一个组件:anchor: jFrame, jApplet, jPanel

其他省略,要用去查

pluggable Look-and-feel:类似展示外观,可以在其他os模拟Windows等

MVC架构: Model (store and handle data), View (present data), Controller

19-Networking

new一个Server socket去监听窗口,server和client进行数据交流:

// Server Host
ServerSocket server = new ServerSocket(8000);
Socket socket = server.accept();

// Client Host
Socket socket = new Socket(host, 8000);

who is connecting to the server? => InetAddress Class:

InetAddress inetAddress = socket.getInetAddress();
System.out.println("Client's host name is"  inetAddress.getHostName());
System.out.println("Client's IP address is"  inetAddress.getHostAddress());

multiple clients:

while(true) {
    Socket socket = serverSocket.accept()
    Thread thread = new ThreadClass(socket);
    thread.start();
}

retrieving files from web servers: java.net.URL class

try {
    URL url = new URL("http://www.sun.com");
    InputStream inputStream = url.openStream();
} catch(MalformedURLException ex) {}

Stream Socket (use TCP) vs. Datagram Socket (use UDP)

20-Multithreading

方法一:实现一个runnable的类

(这里start a thread实际上是线程ready,但是具体什么时候开始还得看调度等)

  • run()需要@Override
  • run()里面加上Thread.yield();的意思是放弃时间片,进行线程调度

方法二:继承Thread

public class HelloThread extends Thread {
    public void run() {
        System.out.println("hello");
    }
    public static void main(String[] args) {
        Thread thread = new HelloThread();
        thread.start(); // create a new thread
        // thread.run(); 打印相同结果,但是此时没有创建新线程
        // Thread.currentThread().getName()
    }
}

:anchor: The Thread Class

interrupt改变中断状态但不会中断正在运行的线程,它中断一个阻塞的程序,使它退出阻塞状态,抛出InterruptException中断异常。

较通用的终止线程方式:

@Override
public void run() {
    try {
        // isInterrupted(): 中断标记为true就终止线程
        while (!isInterrupted()) {
            ...
        }
    } catch (InterruptedException ie) {}
}

daemon线程:辅助线程,程序中只剩下daemon线程时,就会退出。

GUI Event Dispatcher  Thread: GUI event handling and painting code executes in it.

耗时的任务不放在EDT里,而是放在单独的线程里,避免阻塞界面更新与绘制

线程之间能共享内存,访问/操作相同的对象

Race condition: 两个线程同时访问同一个资源 (解决=>线程安全)

  • volatile关键词,强迫所有线程对变量的修改都反映到内存里

  • synchronized关键词,修饰函数/任意代码块,防止多线程访问(隐式锁)

    public synchronized void xMethod() {
        // omitted
    }
    <==>
    public void xMethod() {
        synchronized (this)  {
            // omitted
        }
    }
    
  • 显式锁:Lock类,有读锁/写锁,公平(按加锁顺序)/不公平(默认Lock lock = new ReentrantLock(false)

线程状态:

21-Database

JDBC API

22-Lambda, Stream, RTTI

前两者重要,考大题(填空),不会考复杂

p56某一年考试题


HW

:o: Java的字符类型采用的是Unicode编码(char是16-bit)

:o:字节码文件是与平台无关的二进制码,执行时由解释器解释成本地机器码

:o:Java的各种数据类型占用固定长度,与具体的软硬件平台环境无关

:o:Java中,变量名可以用汉字表示

:x:使用方法length()可以获得字符串或数组的长度(字符串可以,数组要用a.length属性)

:o:Big-endian is used to store all multi-byte data types.

class Test {
     public static void main(String[] args) {
        System.out.println(4 + 5 + "" + 3 + 6);
    }
}
// output: 936

:x:All strings are terminated with a null (‘\0’) character.

public class main {
    public void main() {
        System.out.println("Hello world\n");
     }
}
// It compiles but JVM will say it can not find the main() in the class

:o:It is the JVM that translates the byte code into native during the loading of the class.

:x:Java Native Invoking is the way JIT JVM does to make program run faster. (Just-in-time,即时编译)

JIT(即时编译器)并不是编译器。Java源代码首先会被Java编译器(javac)编译成字节码(bytecode),然后在运行时,JIT会将这些字节码转换为本地代码(native code)。

Java Native Invoking(JNI)是用于调用本地(非Java)代码的接口,而不是JIT提升性能的主要机制。JIT通过在运行时将字节码翻译为本地代码,而与JNI并不直接相关。

public class Q {
    public static void main(String argv[]){
        int anar[]=new int[5];
        System.out.println(anar[0]);
    }
}
// output: 0
// 注意和方法中局部变量未初始化(编译错误)的情况区分

设有变量定义:short a = 300;,则以下哪条语句会导致编译错误?(short: 16-bit, int: 32-bit)

A. a += 3;

:o:B. a = (short)a + 3;

C. a = (byte)(a + 3);

D. a = (short)(a * 100);

tbc...

results matching ""

    No results matching ""