本文为已归档的历史博客内容,其内容可能随着时间发生已经改变。
This article is archived from my previous blog, so the content maybe have changed now.


源自《[Java 4 Android](http://study.163.com/course/courseMain.htm?courseId=201001)》-- [Mars](http://www.marschen.com/portal.php) 如有错误,希望指出。

前言: 本文档不能保证完全正确,如有错误,希望可以指出,但不再另行通知。本文仅作整理及个人学习使用,版权仍归视频作者 Mars 所有。

笔记:

Info:

  • Java SE 1.8
  • Mac OS X 10.10
  • 本文已于 2015.11.17 日基本完成,由于 J4A 系列视频仅有 54 集,后续不知去向,暂且如此,综合练习的代码未来可能会更新于此

面向对象基础

(一)

笔记:

什么是面向对象? - 面向对象时一种编程方法 - 面向对象是一种思维方式 - 面向对象是一种编程语言

如何学习面向对象? - 掌握一门面向对象语言的语法 - 掌握面向对象的思维方式 - 熟悉面向对象设计原则 - 掌握面向对象的设计模式

面向对象最终目标:消除重复代码

什么是面向对象思维模式? - 首先确定谁来做,其次确定怎么做 - 首先考虑整体,其次考虑局部 - 首先考虑抽象,其次考虑具体

(二)

笔记:

定义类:

class 类名
{
	属性(即成员变量);
	方法(即成员函数);
}

类的表示方法:类名+成员变量+成员函数

如果一个方法中有与成员变量同名的局部变量,该方法中对这个变量名的访问是局部变量,而不再是成员变量。

内存占用

对象是引用数据类型: - JVM 将其分成两个内存:栈内存+堆内存 - 栈内存存放对象的名字,即引用(其本身并不是对象) - 对象的本体存放在堆内存(new 的时候开辟空间)

Dog d = new Dog();
// d 不是对象,而是对象的引用

类是抽象的,对象是具体的

(三)

笔记:

生成多个对象

匿名对象(一次性):

new Dog().jump();
new Dog().jump();
// 这两个对象并不一样

(四)

笔记:

重载 - 两个或者多个函数在同一个类当中 - 函数名相同 - 参数列表不同

构造函数: - 如果类中没有构造函数,编译器会生成默认构造函数(参数和方法体为空); - 如果类中已有构造函数(无论参数是否为空),那么就没有默认的构造函数。

this 的使用方法

笔记:

this 调用函数: - 调用本类当中的其它构造函数函数:this.test(name, age); - 必须放在构造函数语句的第一个 - 根据参数个数或类型判断调用哪个构造函数

Static 关键字的作用

笔记:

静态变量:

class Person {
	static int i;
}
Person p1 = new Person();
Person p2 = new Person();
Person.i = 10; // 均 10
p1.i = 20; // 均 20
p2.i = 30; // 均 30

调用静态变量可以(非必须)直接通过类名调用 只要更改 static 变量,所有对象中成员变量值均改变 static 变量是属于类的,不属于对象

静态函数:

class Person {
	static void fun() {
		System.out.println("I am static function.");
	}
}
Person.fun();

调用静态函数可以(非必须)直接通过类名调用 静态函数内不能使用非静态成员变量

静态代码块:

static {
	System.out.println("I am static code block.");
}

静态代码块要在装载(到内存)这个类的时候执行 可以为静态成员变量赋一些初始值(不常用)

继承

继承初步

笔记:

Java 只支持单继承,不允许多继承 继承是为了减少重用代码

eg:

class Person {
	String name;
	int age;
	
	void eat() {
		System.out.println("Have meals.");
	}
	
	void introduce() {
		System.out.println("Name is" + name + "Age is" + age);
	}
}
class Student extends Person {
	int grade;
	
	void study() {
		System.out.println("Study");
	}
}

子类实例化过程

笔记:

只能继承成员函数和成员变量(不继承构造函数) 在子类的构造函数中,必须调用父类构造函数(为什么?) 没有主动调用的话,编译器会自动为你调用(super();) 如果想调用其它构造函数,可以填对应的参数

为什么子类必须调用父类构造函数? - super(); - 继承时不能继承构造函数

eg:

Person.java

class Person {
	String name;
	int age;
	
	Person() {
		System.out.println("Person Non-Paraments");
	}
	
	Person(String name, int age) {
		this.name = name;
		this.age = age;
		System.out.println("Person With-Paraments");
	}
	
	void eat() {
		System.out.println("Have meals.");
	}
}

Student.java

class Student extancds Person {
	student() {
		System.out.println("Student Non-parament");
	}

}

Test.java

class Test {
	public static void main(String args []) {
		Student stu = new Student();
	}
}

函数的复写(Override)

eg:

Person.java

class Person {
	String name;
	int age;
	
	void introduce() {
		System.out.println("My name is" + name + ", I am" + age + "years old.");
	}
}

Student.java

class Student extends Person {
	String address;
	
	void introduce() {
		super.introduce();
		System.out.println("My address is" + address + ".");
	}
}

Test.java

class Test {
	public static void main(String args []) {
		Student s = new Student();
		s.name = "MaiMieng";
		s.age = 20;
		s.address = "USA";
		s.introduce();
		
		Person p = new Person();
		p.name = "Vitas";
		p.age = 30;
		p.address = "Russia";
		P.introduce();
	}
}

笔记:

复写(Override) - 在具有父子关系的两个类中 - 父类和子类各有一个函数,这两个函数的定义(返回值类型,函数名,和参数列表)完全相同 - 用 super. 调用父类相同的成员函数

重载(Overload)和复写(Override)的不同: - 重载是在同一个类,复写是在两个类中 - 重载函数的参数个数或类型不同,而复写完全相同

对象的转型

向上转型:

笔记:

// class Student extends Person:
Student s = new Student();
Person p = s;

Person P = new Student();
  • 对象的向上转型:将子类的对象赋值给父类的引用。

    Student s = new Student();
    Person p = s;
    Student stu = (Student)p;
    

一个引用能够调用那些成员(变量和函数),取决于这个引用的类型 一个引用调用的是哪一个方法,取决于这个引用所指向的对象

eg:

Person.java

class Person {
	String name;
	int age;
	
	void introduce() {
		System.out.println("My name is" + name + ", I am" + age + "years old.");
	}
}

Student.java

class Student extends Person {
	String address;
	
	void study() {
		System.out.println("Studying");
	}
	void introduce() {
		super.introduce();
		System.out.println("My address is" + address + ".");
	}
}

Test.java

class Test {
	public static void main(String args []) {
		Student s = new Student();
		Person p = s;
		
		p.name = "MaiMieng";
		p.age = 20;
//	p.address = "USA";
// 	p.study();
// 	THESE ARE MISTAKES!
		p.introduce();
// 	DISPLAY:
// 	My address is NULL.
	}
}

向下转型

笔记:

对象的向下转型:将父类的对象赋值给子类的引用 向下转型的前提是向上转型

eg:

相比向上转型,仅改变:Test.java

class Test {
	public static void main(String args []) {
		Person p = new Student();
		Student s = (Student)p;
		
		// 错误的向下转型:
		// Person p = new Person();
		// Student s = (Student)p;
	}
}

面向对象应用

eg:

Printer.java

class Printer {
	void open() {
		System.out.println("Open");
	}
	void close() {
		System.out.println("Close");
	}
	
	void print(String s) {
		System.out.println("Print -> " + s);
	}
}

HPPrinter.java

class HPPrinter extends Printer {
	
}

CanonPrinter.java

class CanonPrinter extends Printer {
	void close() {
		this.clean();
		super.close();
	}
	
	void clean() {
		System.out.println("Clean");
	}
}

Test.java

class Test {
	public static void main(String args []) {
		int flag = 0;
		
		if(flag == 0) {
			HPPrinter hp = new HPPrinter();
			hp.open();
			hp.print("hp");
			hp.close();
		} else if (flag == 1) {
			CanonPrinter canon = new CanonPrinter();
			canon.open();
			canon.print("Canon");
			canon.clean();
			canon.close();
	}
}

抽象类和抽象函数

笔记:

abstract void fun();

抽象函数:只有函数的定义,没有函数体的函数

抽象(基)类:使用 abstract 定义的类 - 抽象类不能生成对象(无法实例化),但可以有构造函数(详见下) - 如果一个类中有抽象函数,则该类必须被声明为抽象类 - 如果一个类没有抽象函数,则该类也可被声明为抽象类

eg:

Person.java

abstract class Person {
	String name;
	int age;
	
	Person() {
		System.out.println("Person's construction.");
	}
	
	void introduce() {
		System.out.println("My name is" + name + ", I am" + age + "years old.");
	}
	abstract void eat();
}

Chinese.java

class Chinese extend Person {
	Chinese() {
		// super();
		System.out.println("Chinese's construction.");
	}
	void eat() {
		System.out.println("Chinese Food.");
	}
}

Test.java

class Test {
	public static void main(String args []) {
		Person p = new Chinese();
		p.eat();
}

包和访问权限

(一)

笔记:

编译参数:

// -d: 根据包名生成文件夹
javac -d . Test.java

java test.Test

软件包为 Java 类提供了命名空间 打包需要使用 package 指令(package test;) 一个类的全名应该是:"包名" + "." + "类名"

包名的命名规范: - 要求包名的所有字母都要小写 - 包名一般情况下,是你的域名倒过来写:package com.maimieng(将会先生成 com 文件夹) - 建议 package com.maimieng.+...

(二)

笔记:

访问权限: - public: 公共权限 - private: 私有权限 - (default): 包级别访问权限 - protected: 受保护权限

public:

如果一个类是 public,那么这个类名必须和 .java 文件名相同 public 可以修饰类,成员变量和成员函数 没有任何限制,同一个包或者不同包中的类都可以自由访问

private:

一般只修饰成员(变量和函数) 一旦成员被 private 修饰,那么其只能在本类中使用

(default):

  • 在同一个包当中,可以互相访问。

import:

导入其它包的类(即可省略包的全名:com.maimieng.Person = new com.maimieng.Person();):

import com.maimieng.Person;
import com.maimieng.*;
// 导入此目录下全部类

(三)

笔记:

如果子类和父类不在同一个包当中,子类可以继承到父类当中的 (default) 权限的成员变量和成员函数,但是由于权限不够,无法使用

protected 该权限只能修饰成员变量和成员函数 父类的 protected 可以为跨包的子类所用

public > protected > (default) > private

接口的基本语法

笔记:

class USBphone implements USB {}

定义了接口就是定义了调用对象的标准 接口中所有方法为 public 权限 实现接口使用 implements 关键字 一个类可以实现多个接口 一个接口可以继承多个接口

eg:

一个类实现两个接口

USBphone.java

class USBphone implements USB, Wifi {

	@Override
	public void read() {
		System.out.println("READ");
	}

	@Override
	public void write() {
		System.out.println("WRITE");
	}

	@Override
	public void open() {
		System.out.println("OPEN");
	}

	@Override
	public void close() {
		System.out.println("CLOSE");
	}
}

USB.java

interface USB {
	public void read();
	
	public void write();
}

Wifi.java

interface Wifi {
	public void open();
	
	public void close();
}

Test.java

public class Test {
	public static void main(String args []) {
		USBphone up = new USBphone();
		USB usb = up;
		usb.read();
		usb.write();
		
		Wifi wifi = up;
		wifi.open();
		wifi.close();
	}
}

一个接口继承两个个接口

A.java

interface A {
	public void funA();
}

B.java

interface B {
	public void funB();
}

C.java

interface C extends A, B {
	public void funC();
}

接口的应用

Printer.java

interface Printer {
	public void open();
	public void close();
	public void print(String s);
}

HPprinter.java

class HPprinter implements Printer {

	@Override
	public void open() {
		System.out.println("HP open");
	}

	@Override
	public void close() {
		System.out.println("HP close");
	}

	@Override
	public void print(String s) {
		System.out.println("HP -> " + s);
	}
}

CANONprinter.java

class CANONprinter implements Printer {
	
	private void clean() {
		System.out.println("CANON clean");
	}
	
	@Override
	public void open() {
		System.out.println("CANON open");
	}

	@Override
	public void close() {
		this.clean();
		System.out.println("CANON close");
	}

	@Override
	public void print(String s) {
		System.out.println("CANON -> " + s);
	}
}

PrinterFactory.java

class PrinterFactory {
	public static Printer getPrinter(int flag) {
		Printer p = null;
		if (flag == 0) {
			p = new HPprinter();
		} else if (flag == 1) {
			p = new CANONprinter();
		}
		return p;
	}
}

Test.java

public class Test {
	// 根据用户的选择,生成相应的打印机对象
	// 并且向上转型为 Printer 类型
	// Printer getPrinter(int flag);
	public static void main(String args []) {
		int flag = 1;
		Printer p = PrinterFactory.getPrinter(flag);
		p.open();
		p.print("test");
		p.close();
	}
}

Java 当中的异常

(一)

笔记:

异常的分类:

异常的分类

异常(Exception):中断了正常指令流的事件 - 异常不同于语法错误,运行时产生,不同于编译时 - 异常是一个对象,由 JDK 中的类生成(如上图) - 分为两类:运行时异常(Uncheck, RuntimeException 子类),编译时异常(Check) - 对异常的处理关系到系统的健壮性 - 使用 try catch finally 处理可能出现异常的代码

Error: 虚拟机在运行的时候产生的错误,然后直接关闭 程序员对 Error 无能为力,只能处理 Exception

eg:

public class Test {
	public static void main(String args []) {
		// Uncheck exception:
		// int i = 1 / 0;
		
		// Check exception:
		Thread.sleep(1000);
	}
}
public class Test {
	public static void main(String args []) {
		System.out.println(1);
		try {
			System.out.println(2);
			int i = 1 / 0;
			System.out.println(3);
		}
		catch (Exception e) {
			System.out.println(4);
			e.printStackTrace();
			System.out.println(5);
		}
		System.out.println(6);
	}
}
public class Test {
	public static void main(String args []) {
		try {
			Thread.sleep(1000);
		}
		catch (Exception e) {
			e.printStackTrace();
		}
		finally {
			// 放一些诸如文件关闭等关闭资源的操作
			System.out.println("Finally");
		}
	}
}

(二)

eg:

User.java

class User {
	private int age;
	// 声明有可能产生异常(即其没有责任处理异常,谁调用谁处理):
	public void setAge(int age) throws Exception {
		if (age < 0) {
			Exception r = new Exception("TEST");
			
			// 抛出异常:
			throw r;
		}
		this.age = age;
	}
}

Test.java

class Test {
	public static void main(String args []) {
		User u = new User();
		try {
			u.setAge(-20);
		}
		catch (Exception e)  {
			System.out.println("Test");
		}
	}
}

Java 当中的 IO

(一)

笔记:

I/O 操作的目标:从数据源当中读取数据,以及将数据写入到数据目的地当中

I/O 流向:

I/O 流向

IO 分类: 一: 1. 输入流 2. 输出流

二: 1. 字节流 2. 字符流

三: 1. 节点流 2. 处理流

I/O 当中的核心类:

I/O 当中的核心类

InputStream & OutputStream(抽象类)是所有字节流的父类

核心类的核心方法:

// InputStream
int read(byte[] b, int off, int len)

// OutputStream
void write(byte[] b, int off, int len)

eg:

// 导入类
import java.io.*;

class Test {
	public static void main(String args []) {
		// 声明输入流引用
		FileInputStream f = null;
		// 声明输出流引用
		FileOutputStream o = null;
		try {
			// 生成代表输入流的对象
			f = new FileInputStream("/Users/MaiMieng/Documents/workspace/1.txt");
			// 生成代表输出流的对象
			o = new FileOutputStream("/Users/MaiMieng/Documents/workspace/2.txt");
			
			// 生成一个字节数组
			byte[] buffer = new byte[100];
			
			// 调用输入流对象的 read 方法,读取数据
			int t = f.read(buffer, 1, buffer.length - 1);
			o.write(buffer, 0, t);
			
			// String s = new String(buffer);
			// System.out.println(s);
			// 调用一个 String 对象的 trim 方法,将会去除掉这个字符串的首尾空格和空字符
			// s.trim();
			// for (int i = 0; i < buffer.length; i++) {
			// 	System.out.println(buffer[i]);
			//}
		}
		catch (Exception e) {
			System.out.println(e);
		}
	}
}

(二)

笔记:

字符流:读写文件时,以字符为基础 字节输入流:Reader <- FileReader 字节输出流:Writer <- FileWriter

int read(char [] c, int off, int len)
void write(char [] c, int off, int len)

eg:

字节流:

import java.io.*;

class Test {
	public static void main(String args []) {
		FileInputStream i = null;
		FileOutputStream o = null;
		try {
			i = new FileInputStream("/Users/MaiMieng/Documents/workspace/1.txt");
			o = new FileOutputStream("/Users/MaiMieng/Documents/workspace/2.txt");
			
			byte[] buffer = new byte[1024];
			
			while (true) {
				int t = i.read(buffer, 1, buffer.length - 1);
				if (t == -1) {
					break;
				}
				o.write(buffer, 0, t);
			}
		}
		catch (Exception e) {
			System.out.println(e);
		}
		finally {
			try {
				i.close();
				o.close();
			}
			catch (Exception e) {
				System.out.println(e);
			}
		}
	}
}

字符流:

import java.io.*;

class Test {
	public static void main(String args []) {
		FileReader fr = null;
		FileWriter fw = null;
		try {
			fr = new FileReader("/Users/MaiMieng/Documents/workspace/1.txt");
			fw = new FileWriter("/Users/MaiMieng/Documents/workspace/2.txt");
			char[] buffer = new char[100];
			int t = fr.read(buffer, 0, buffer.length);
//			for (int i = 0; i < buffer.length; i++) {
//				System.out.println(buffer[i]);
//			}
			fw.write(buffer, 0, t);
			
		}
		catch (Exception e) {
			System.out.println(e);
		}
		finally {
			try {
				fr.close();
				fw.close();
			}
			catch (Exception e) {
				System.out.println(e);
			}
		}
	}
}

(三)

笔记:

字符输入处理流 BufferedReader 介绍: - 读取一行数据

BufferedReader in = new BufferedRead(new FileReader("foo.in"));

eg:

Test.java

import java.io.*;

class Test {
	public static void main(String args []) {
		FileReader fr = null;
		BufferedReader br = null;
		
		try {
			fr = new FileReader("/Users/MaiMieng/Documents/workspace/1.txt");
			br = new BufferedReader(fr);
			String l = null;
			while (true) {
				l = br.readLine();
				if (l == null) {
					break;
				}
				System.out.println(l);
			}
		}
		catch (Exception e) {
			System.out.println(e);
		}
		finally {
			try {
				br.close();
				fr.close();
			}
			catch (Exception e) {
				System.out.println(e);
			}
		}
	}
}

装饰者模式:装饰者给被装饰者提供功能

Aworker.java

// Aworker 是装饰者,Carpenter & Plumber 是被装饰者
class Aworker implements Worker {
	private Worker worker;
	public Aworker(Worker worker) {
		this.worker = worker;
	}
	public void doSomeWork() {
		// 先执行都需要执行的函数,再转型
		System.out.println("Hello");
		worker.doSomeWork();
	}
}

内部类和匿名内部类

笔记:

内部类:

class A {
	// B 是 A 的内部类,编译后生成 A$B.class
	class B {
		...
	}
}

内部类可以使用外部类的成员变量和成员函数,但并不代表内部类是外部类的继承

匿名内部类:

eg:

内部类:

Test.java

class Test {
	
	public static void main(String args []) {
		A a = new A();
		
		// 生成内部类对象,必须先有外部类对象
		A.B b = a.new B(); 
		// 类似:A.B b = new A().new B();
		
		a.i = 1;
		b.j = 2;
		System.out.println(b.funB());
	}
}

A.java

class A {
	int i;
	class B {
		int j;
		int funB() {
			int r = i + j;
			// 类似:int r = A.this.i + this.j;
			return r;
		}
	}
}

匿名内部类:

Test.java

class Test {
	public static void main(String args []) {
		B b = new B();
		b.fun(new A() {
			// 用来实现 A 的接口:
			public void doSome() {
				System.out.println("匿名内部类");
			}
		});
	}
}

A.java

interface A {
	public void doSome();
}

B.java

class B {
	public void fun(A a) {
		System.out.println("B's fun()");
		a.doSome();
	}
}

Java 当中的线程

(一)

笔记:

多进程:在操作系统中能(同时)运行多个任务(程序) 多线程:在同一应用程序中有多个顺序流(同时)执行

线程的执行过程:

单线程的执行过程

多线程的执行过程

执行过程

实现线程的方法 1: - 定义一个线程类,它继承类 Thread 并重写其中的方法 run(),方法 run() 称为线程体(由于 Java 只支持单继承,用这种方法定义的类不能再继承其它类)

线程运行没有规律

eg:

Test.java

class Test {
	public static void main(String args []) {
		// 生成线程类的对象
		FirstThread ft = new FirstThread();
		
		// 启动线程,不能这样写:ft.run();(这个先执行 ft 线程)
		ft.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("M: " + i);
		}
	}
}

FirstThread.java

class FirstThread extends Thread {
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("FT: " + i);
		}
	}
}

(二)

笔记:

实现线程的方法 2: 提供一个实现接口 Runnable 的类作为线程的目标对象,在初始化一个 Thread 类或者 Thread 子类的线程对象时,把目标对象传递给这个线程实例,由该目标对象提供线程体 线程的简单控制方法: - 中断线程

Thread.sleep(x);(要使用 try catch,休眠时间= x 毫秒+抢到 CPU 的时间) Thread.yield();(让出 CPU,同时再次去抢,并不一定是另一个线程运行)

  • 设置线程优先级:

getPriority(); setPriority();

eg:

实现线程:

RunnableImpl.java

class RunnableImpl implements Runnable {
	public void run() {
		for (int i = 0; i < 100; i++) {
			System.out.println("RI: " + i);
		}
	}
}

Test.java

class Test {
	public static void main(String args []) {
		// 生成一个 Runnable 接口实现类的对象
		RunnableImpl ri = new RunnableImpl();
		// 生成一个 Thread 对象,并将 Runnable 接口实现类的对象作为参数,传递给该 Thread 对象
		Thread t = new Thread(ri);
		// 通知 Thread 对象,执行 start 方法
		t.start();
		
		for (int i = 0; i < 100; i++) {
			System.out.println("M: " + i);
		}
	}
}

优先级等

Test.java

class Test {
	public static void main(String args []) {
		// 生成一个 Runnable 接口实现类的对象
		RunnableImpl ri = new RunnableImpl();
		// 生成一个 Thread 对象,并将 Runnable 接口实现类的对象作为参数,传递给该 Thread 对象
		Thread t = new Thread(ri);
		// 线程优先级范围:1-10,可通过 Thread 静态常量来设置线程优先级
		t.setPriority(Thread.MIN_PRIORITY);
		System.out.println(t.getPriority());
		
		// 通知 Thread 对象,执行 start 方法
		t.start();
	}
}

(三)

eg:

Test.java

class Test {
	
	public static void main(String args []) {
		MyThread myThread = new MyThread();
		// 生成两个 Thread 对象,但是它们共用同一个线程体
		Thread t1 = new Thread(myThread);
		Thread t2 = new Thread(myThread);
		// Thread 每一个线程都有名字,可通过 setName() 设置,getName() 获取
		t1.setName("a");
		t2.setName("b");
		// 分别启动两个线程
		t1.start();
		t2.start();
	}
}

MyThread.java

class MyThread implements Runnable {
	int i = 100;
	public void run() {
		// 谁获得谁才能运行:
		synchronized (this) {
			while (true) {
				// Thread.currentThread() 获取哪个线程在运行
				System.out.println(Thread.currentThread().getName() + i);
				i--;
				Thread.yield();
				if (i < 0) {
					break;
				}
			}
		}
		
	}
}

深入同步语法

笔记:

同步代码块: - synchronized() 锁住的是对象(thisservice)而不代码 - 一旦某个线程获得了一个对象的同步锁,那么这个对象上任何被同步的代码统统不能执行 - 同步锁不影响非同步代码

同步方法锁住的是 thisthis 即调用此方法的对象),与同步代码块类似,但同步代码块更灵活(括号内可以放其它对象)

eg:

同步代码块:

Main.java

public class Main {

	public static void main(String[] args) {
		Service s = new Service();
		
		Thread t1 = new Thread(new MyThread1(s));
		Thread t2 = new Thread(new MyThread2(s));
		
		t1.start();
		t2.start();
	}
}

MyThread1.java

class MyThread1 implements Runnable {
	private Service s;
	
	public MyThread1(Service s) {
		this.s = s;
	}
	
	public void run() {
		s.fun1();
	}
}

MyThread2.java

class MyThread2 implements Runnable {
	private Service s;
	
	public MyThread2(Service s) {
		this.s = s;
	}
	
	public void run() {
		s.fun2();
	}
}

Service.java

class Service {
	public void fun1() {
		synchronized(this) {
			try {
				Thread.sleep(3 * 1000);
			}
			catch(Exception e) {
				System.out.println(e);
			}
			System.out.println("fun1");
		}
	}
	
	public void fun2() {
		synchronized(this) {
			System.out.println("fun2");
		} 
	}
}

// DISPLAY:
// fun1
// fun2

不会对无同步锁代码屏蔽:

Service.java

class Service {
	public void fun1() {
		synchronized(this) {
			try {
				Thread.sleep(3 * 1000);
			}
			catch(Exception e) {
				System.out.println(e);
			}
			System.out.println("fun1");
		}
	}
	
	public void fun2() {
		// synchronized(this) {
			System.out.println("fun2");
		//  } 
	}
}

// DISPLAY:
// fun2
// fun1

同步方法:

Service.java

class Service {
	public synchronized void fun1() {
		try {
			Thread.sleep(3 * 1000);
		}
		catch(Exception e) {
			System.out.println(e);
		}
		System.out.println("fun1");
	}
	
	public synchronized void fun2() {
		System.out.println("fun2");
	}
}

// DISPLAY:
// fun1
// fun2

Java 当中的数组

笔记:

数组长度:.length 动态声明的数组默认值均为 0false

eg:

一维数组:

Main.java

class Main {

	public static void main(String[] args) {
		// 数组的静态声明法:
		int arr [] = {5, 2, 7, 9};
		
		// 数组的动态声明法:
		int a [] = new int[10];
		
		arr[3] = 10;
		
		System.out.println(arr[3]);
		
		for (int i = 0; i < arr.length; i++) {
			System.out.println(arr[i]);
		}
	}
}

// DISPLAY:
// 10
// 5
// 4
// 7
// 10

二维数组:

class Main {

	public static void main(String[] args) {
		// 二位数组的定义方法:
		int arr [][] = {{1, 2, 3}, {4, 5, 6}, {7, 8}};
		int a [][] = new int[3][5];
		
		arr[1][1] = 10;
		
		System.out.println(arr[1][1]);
		
		for (int i = 0; i < arr.length; i++) {
			for (int j = 0; j < arr[i].length; j++) {
				System.out.println(arr[i][j]);
			}
		}
	}
}

// DISPLAY:
// 10
// 1
// 2
// 3
// 4
// 10
// 6
// 7
// 8

类集框架

(一)

笔记:

类集框架是一组类和接口 位于 jav.util 包中 主要用户存储和管理对象 主要分为三大类:集合,列表,映射

集合(Set): 集合中的对象不按特定的方式排序,并且没有重复对象

列表(List): 集合中对象按照索引位置排序,可以有重复对象

映射(Map): 集合中的每一个元素包涵一个键对像和一个值对象,键不可以重复,值可以重复

类集框架主体结构

类集框架主体结构

eg:

Main.java

import java.util.List;
import java.util.ArrayList;

class Main {
	public static void main(String[] args) {
		ArrayList<String> arrayList = new ArrayList<String>();
		
		arrayList.add("a");
		arrayList.add("b");
		arrayList.add("c");
		
		arrayList.remove(1);
		
		for (int i = 0; i < arrayList.size(); i++) {
			String s = arrayList.get(i);
			System.out.println(s);
		}
	}
}

// DISPLAY:
// a
// c

(二)

笔记:

Collection 接口:

Collection 接口

继承关系: Iterator <- Collection <- Set <- HashSet Iterator <- Collection <- List <- ArrayList

eg:

Main.java

1:

import java.util.Set;
import java.util.HashSet;

class Main {
	public static void main(String[] args) {
//		HashSet<String> hashSet = new HashSet<String>();
//		Set<String> set = hashSet;
		Set<String> set = new HashSet<String>();
		
		boolean b1 = set.isEmpty();
		System.out.println(b1);
		
		set.add("a");
		set.add("b");
		set.add("c");
		set.add("d");
		set.add("c");
		
		boolean b2 = set.isEmpty();
		System.out.println(b2);
		System.out.println(set.size());
		
		set.remove("a");
		System.out.println(set.size());
		
		set.clear();
		System.out.println(set.size());
	}
}

// DISPLAY:
// true
// false
// 4
// 3
// 0

2:

import java.util.Set;
import java.util.HashSet;
import java.util.Iterator;

class Main {
	public static void main(String[] args) {
		Set<String> set = new HashSet<String>();
		
		set.add("a");
		set.add("b");
		set.add("c");
		set.add("d");
		set.add("c");
		
		// 调用 Set 对象的 Iterator 方法,
		// 会生成一个迭代器对象,
		// 该对象用于遍历整个 Set
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			String s = it.next();
			System.out.println(s);
		}
		
	}
}

(三)

笔记:

学会使用 api 文档(推荐一个 iOS & Mac app:dash)

eg:

Main.java

import java.util.Map;
import java.util.HashMap;

class Main {
	public static void main(String[] args) {
		HashMap<String, String> hashMap = new HashMap<String, String>();
		Map<String, String> map = hashMap;
		
		map.put("1", "a");
		map.put("2", "b");
		map.put("3", "c");
		map.put("4", "d");
		map.put("3", "e");
		
		System.out.println(map.size());
		System.out.println(map.get("3"));
	}
}

// DISPLAY:
// 4
// e

equals 函数的作用

笔记:

使用 == 比较引用数据类型: 判断双等号两端的引用是否指向堆内存中的同一个地址/对象

对象的内容相等*通常*需要符合: 1. 对象的类型相同(可以用 instanceof 操作符进行比较) 2. 两个对象的成员变量的值完全相同

eg:

Main.java

class Main {
	public static void main(String[] args) {
		User u1 = new User();
		User u2 = new User();
		User u3 = new User();
		
		u1.name = "Mike";
		u1.age = 12;
		
		u2.name = "Michael";
		u2.age = 12;
		
		u3.name = "Mike";
		u3.age = 12;
		
		System.out.println(u1.equals(u2));
		System.out.println(u1.equals(u3));
				
				
	} 
}

// DISPLAY:
// false
// true

User.java

class User {
	String name;
	int age;
	
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		
		boolean b = obj instanceof User;
		if (b) {
			User u = (User)obj;
			if (this.age == u.age && this.name.equals(u.name)) {
				return true;
			} else {
				return false;
			}
		} else {
			return false; 
		}
			
	}
}

hashCode()toString()

笔记:

均为 Object 类函数

eg:

Main.java

import java.util.*;

class Main {
	public static void main(String[] args) {
		User u = new User("Mike", 12);
		
		HashMap<User, String> map = new HashMap<User, String>();
		
		map.put(u, "abc");
		String s = map.get(new User("Mike", 12));
		System.out.println(s);
		
		System.out.println(u);
	} 
}

// DISPLAY:
// abc
// age: 12, name: Mike

User.java

class User {
	String name;
	int age;
	
	public User() {
		
	}
	
	public User(String name, int age) {
		this.name = name;
		this.age = age;
	}
	
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		
		boolean b = obj instanceof User;
		if (b) {
			User u = (User)obj;
			if (this.age == u.age && this.name.equals(u.name)) {
				return true;
			} else {
				return false;
			}
		} else {
			return false; 
		}
	}
	
	public int hashCode() {
		int result = 17;
		
		result = 31 * result + age;
		result = 31 * result + name.hashCode();
		
		return result;
	}
	
	public String toString() {
		String result = "";
		result = result + "age: " + age + ", " + "name: " + name;
		return result;
	}
}

开发工具之 Eclipse

(一)&(二) &(三)

(四)

笔记:

代码重构: 重构可以改善软件的设计 重构可以让软件更加容易理解 重构可以协助寻找 bug 重构可以提升开发速度

综合练习

暂无