专注、坚持

初学 Java 4 Android - Note & Code

2015.09.13 by kingcos
Preface · 序
本文为已归档的历史博客内容,其内容可能随着时间发生已经改变。
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 重构可以提升开发速度

综合练习

暂无