资讯专栏INFORMATION COLUMN

Java 学习笔记

tianlai / 1708人阅读

摘要:参考资料程序设计北大唐大仕零基础学语言浙大翁恺面向对象程序设计语言浙大翁恺在里面搜索可以查看和修改快捷键自动补全代码格式化简介历史与一起发展万维网所有信息用链接连接起来静态网页动态网页的出现年开发工具包语法增加广泛动态编译脚本

参考资料

Java程序设计 - 北大 - 唐大仕

零基础学Java语言 - 浙大 - 翁恺

面向对象程序设计——Java语言 - 浙大 - 翁恺

Eclipse

在preference里面, 搜索keys, 可以查看和修改快捷键

Content Assist, 自动补全

Format, 代码格式化


1. Java简介 1.1 历史

Java 与 Internet 一起发展

www, 万维网, 所有信息用链接连接起来

Java, 静态网页 -> 动态网页

Java的出现, 1995年, SUN, Stanford University Network, JDK 1.0

JDK, Java Development Kit, Java开发工具包

1995, JDK 1.0
1998, JDK 1.2, Java2
2000, JDK 1.3
2002, JDK 1.4, assert, logging, re
2004, JDK 1.5, 语法增加
2006, JDK 1.6, 广泛, Compiler API(动态编译), 脚本语言支持, WebService支持
2010, Oracle并购SUN
2011, JDK 1.7, 带资源的try, 重抛异常
2014, JDK 1.8, 大改进, lambda表达式

注: 从 JDK 1.5 之后, JDK 1.x 也被称为 JDK x, 如 JDK 1.8 也被叫做 Java 8

Java的推动力

JCP, Java Community Process, 社区

JSR, Java Specification Requests, 规范

1.2 三大平台

Java SE, J2SE, Java 2 Platform Standard Edition, 标准版, 桌面引用

Jave EE, J2EE, Java 2 Platform Enterprise Edition, 企业版, Web应用

Java ME, J2ME, Micro Edition, 微型版, 嵌入式设备


1.3 特点

跨平台, 安全稳定(不易内存溢出), 支持多线程, 丰富的类库

纯的面向对象, 变量和方法都在对象里面

与 C++ 的区别

无直接指针, 自动内存管理

基本数据类型长度固定

不使用头文件

不支持宏

无多重继承(使用接口)

没有(放在类外面的)全局变量

没有 GOTO

1.4.1 Java的编译与运行(IDE, 以 Eclipse 为例)

打开 Eclipse, 然后左上角 File --- New --- Java Project, 输入工程名 javanote --- Finish

在 Package Explorer 中展开 javanote --- 右键 src --- New --- Class, 在 Name 中输入 Main (首字母大写), 这之后我们会在 Package Explorer 中看到新增的 Main.java

编写 Main.java

package javanote;

public class Main{
    public static void main(String args[]) {
        System.out.println("hello world");
    }
}

运行

1.4.2 Java的编译与运行(命令行)

进入新建文件夹 ./javanote, 然后新建源程序文件 Main.java, 注意文件名和 public class 后面的类名一致

public class Main {
    // 注意 String[] args 不能省略
    public static void main(String[] args){
        System.out.println("hello world");
    }
}

编译, 将会得到 Main.class 目标文件(obj), 字节码 bytecode, 扩展名 class .它不是实际机器的最终执行代码

# c 代表 compiler
$ javac Main.java
$ ls
Main.class  Main.java

运行

# 注意不是 java Main.class
java Main

通过 JVM 读取并处理 class 文件, 最终转化成 CPU 的指令. JVM for Win/Unix/ 模拟了一个操作系统/接口

1.5 三种核心机制

Java Virtual Machine, Java虚拟机

源程序(.java 后缀) ---javac--- 字节码(bytecode, .class 后缀) ---java--- 在 JVM 上运行

JVM 规定了虚拟的CPU和内存, 包含以下内容: 寄存器集, 类文件结构, 堆栈, 垃圾收集堆, 内存区域

Code Security, 代码安全性检测

Garbage Collection, 垃圾回收, 自动管理内存

Java 程序不能依赖于垃圾回收的时间或者顺序

GC 是完全自动的, 不能被强制执行, 程序员最多只能用 System.gc()来建议执行垃圾回收器回收内存, 但是具体的回收时间, 是不可知的。当对象的引用变量被赋值为 null, 可能被当成垃圾

GC 自动回收内存, 程序员不需要要无法精确控制回收过程, 也就是说只有 new, 没有 delete

系统级线程会跟踪存储空间的分配情况

JVM 空闲时, 检查和释放那些可以释放的空间

1.6 Java 运行环境, JRE, Java Runtime Environment

在具体运行的时候, Java需要一个运行环境, 即 JRE

JRE = JVM + API(Lib)

JRE 运行程序时的三项主要功能

加载代码(class loader), 校验代码(bytecode verifier), 执行代码(runtime interpreter, 因此虚拟机有时候也简单称为一个解释器)

小结: Java运行环境(JRE) 首先由虚拟机 JVM 来装载程序, 然后调用相应的指令来执行

平台无关: 把 class 文件放到不同的系统, 虚拟机可以执行, 不需要重新编译

1.7 Java 层次结构

JDK = JRE + Tools (编译工具 javac, 打包工具 jar, 调试工具 jdb, 执行器 java, 文档生成器 javadoc)

JRE = JVM + API

开发程序需要 JDK, 如果只是运行程序则 JRE 够了

1.8 面向对象简介

类, class, 是抽象的具有共同属性和行为的集合

类 = 属性(变量, 字段, field) + 行为(函数, 方法, method)

对象, object, 对象实例, instance, 一个实体, 一块可以标识的存储区域

三大特征: 封装, 继承, 多态

1.9 简单的 Java 程序

类型: Application(应用程序), Applet(小应用, 嵌入到HTML)


Application 的基本结构

package javanote;

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

// 一个文件可以有多个 class, 但是只能有一个 public class, 且与文件同名
// main 方法必须是 public static
// main 方法是一个特殊的方法, 它是程序运行的入口
// main 还可用于测试, 直接运行该类的时候会调用 main, 如果是其他类调用这个类的方法, 则不会运行 main
// package, 包, 文件路径
// import, 导入其他的类

1.10 输入输出

输入 Scanner, 输出 System.out.print()

package javanote;

import java.util.InputMismatchException;
import java.util.Scanner;

public class Main{
    public static void main(String args[]) {
        try {
            // 注意, 如果输入的不是整数, 而是小数/字符串, 则会报错. 因此需要try...catch...
            Scanner in = new Scanner(System.in);
            int a = in.nextInt();
            System.out.println(a);
        }
        catch (InputMismatchException e) {
            // TODO: handle exception
        }
    }
}

1.11 基本数据类型

整数型

byte, 1 字节

short, 2 字节

int, 4 字节

long, 8 字节

Java 中没有 无符号数

实数, 浮点数

float, 4 字节

double, 8 字节, 浮点数默认是 double

逻辑型

boolean, 1 bit, true/false

Java 中不可以用 if(1)if(0), 也不能 if( a = 5 )

boolean 不能比较大小, 不能进行算术运算

2 + true           // error
true + true        // error, 就算换成 boolean a, b; 然后 a + b; 仍然是error
true > false       // error
1 > false          // error
true == 6;         // error
a == b > false     // error, ==, != 优先级低, 先做 b > false, 这里也会出错
( a == b ) > false // error, 类似于 true > false 的error

逻辑运算的 !, &&, || 只能用于 boolean, 作用到其他类型上面会出错, 这点也和 C 不一样

字符型

char, 2 字节, 统一使用 Unicode 编码, 跨平台

强制类型转换

double a = 10.3;
int b = (int)a;
int c = (int) (10/3.0);
// (10/3.0)要加括号, 因为(int)是单目运算, 优先级高

1.12 对象存储区域

基本数据类型, 变量在栈. 复制变量的时候,复制的是值.

非基本数据类型, 引用类型, 在堆, 变量只是引用, 类似于指针, 只能指向特定对象, 不能乱指, 复制变量的时候,复制的是引用

1.13 数组

数组是一种容器, 所有元素有相同的数据类型, 一旦创建, 则不能改变大小. 数组必须用 new 来分配空间, 数组元素默认初始化.

// 注意方括号的位置

// a和b都是数组, 其中 a 未分配空间, b 分配了 4 个 int 的空间
int[] a, b = new int[4];
// c 是数组, d 是 int 变量
int c[], d;

数组是引用类型, 元素个数可以用变量定义,

// 数组是引用类型
int[] a1 = new int[3];
int b = 10;
// 元素个数可以用变量定义, 和c99类似
int[] a2 = new int[b];

// error, 数组是引用类型, 理解为指针, 不能直接给它分配空间, 分配的空间在堆, 必须 new 一块空间然后指向那里
int a3[5];

如果没有对数组进行显式初始化, 则会隐式初始化为 0 或 null, 比 C 安全

// 如果没有对数组进行显式初始化, 则会隐式初始化为 0 或 null
int[] a4 = {3, 1, 2};
int[] a5 = new int[]{3, 1, 2};

// 注意, 数组元素会默认初始化, 但是基本数据类型声明后不会默认初始化
int a;
a++;  // error

与指针的类似之处, 数组变量只是数组的管理者, 而不是拥有者

int[] a = new int[10];
int[] b = a;
b[0] = 5;

// 此时 a[0] 也变成了 5
// a == b 的结果是 true

复制数组, 不能用 b = a, 而需要遍历, 除此以外还有 a.clone()System.arraycopy(src, int srcPos, dst, int dstPos, int length) 方法

int[] a = {1, 2, 3, 4};
// 方法1, a.clone()
int[] b = a.clone();

int[] c = new int[4];
// 方法2, System.arraycopy()
System.arraycopy(a, 0, c, 0, a.length);

每个数组, 都有一个 .length 属性, 比 C 安全

int[] a = new int[10];
for( int i = 0; i < a.length; i++ ) {  }

// 也可以这样遍历, 因为数组是个 Iterable 对象
for( int n : a ) {  }

二维数组

int[][] a = new int[3][5];
for( int i = 0; i < a.length; i++ ) {
    for( int j = 0; j < a[0].length; j++ ) {
        a[i][j] = i * 5 + j; 
    }
}

// 初始化
int[][] a = {
    {1, 2, 3, 4},
    {1, 2, 3},
}

// 注意最后可以多一个逗号

1.14 字符, char, 字符串, String

字符类型 char, 能被单引号包围, 如 "a", "+", "你", unicode16编码, 2个字节, 在所有机器上是一致和统一的

字符串, String, 第一个字母大写, 说明是一个类, 是管理者

String s1 = new String("123");
String s2 = "abc";

// 自动转换
String s3 = s1 + s2 + 12 + 24;    // "123abc1224"
String s4 = s1 + s2 + (12 + 24);  // "123abc36"

// 注意
String s5 = null;
System.out.println( s5 + "a" ); // nulla

读取输入

next --- 相当于 C++ 中的 cin
nextLine --- 相当于 C++ 中的 getline

字符串的操作. 字符串是对象, 对它的所有操作都要通过 . 这个运算符

长度, s.length()

注意要加括号 () , 是字符串的 length() 方法, 和数组的 length 属性不一样

而且在调用 .length() 时, s 必须指向一块字符串, 不能是未初始化区域(null)

访问字符, s.charAt(index), 注意这是只读操作, read-only

遍历, 注意字符串无法使用 for(char ch : s), 因为字符串不是 Iterable 对象

for( int i = 0; i < s.length(); i++ ){
    s.charAt(i);
}

子串, .substring()

// [n:-1]
s.substring(n);
// [n, n + len)
s.substring(n, len);

内容是否相同 .equals()

if( s.equals("Hello") ) {  }

比较大小, .compareTo(), unicode 编码相减

s1.compareTo(s2);        // unicode 编码相减

其他操作

int loc = s.indexOf("a");
s.indexOf("a", loc + 1);
s.indexOf("abc");

s.lastIndexOf("a");

s.startsWith(ch);
s.endsWith(ch);
s.trim();            // 去掉两端空格
s.replace(c1, c2);
s.toLowerCase();
s.toUpperCase();

注意, 字符串本身是不可变的. 以上操作如果返回了字符串, 那这些返回的字符串是新生成的, 而不是修改了原来的字符串.

1.15 包裹类型, Wrapper

基本数据类型对应的包裹类型

boolean --- Boolean
byte --- Byte
short --- Short
char --- Character
int --- Integer
long --- Long
float --- Float
double --- Double

基本数据类型 + 更多方法和字段

int a = Integer.MAX_VALUE;        // 2^31 - 1
boolean b = Character.isDigit("a");    // false
char c = Character.toLowerCase("A");    // a

数学类, Math

Math.abs()
Math.round()
Math.random()
Math.pow()

1.16 方法(函数)

实参类型的宽度(尺寸大小)必须 <= 形参类型的宽度(大小)

比如形参 double 实参 int 是可以的, 但是反过来就不行

true 和 int 无法转换

方法的每一次运行, 都会产生独立的本地变量空间, 参数也是本地变量

由于没有 C 的指针, 也没有 C++ 的引用 &, 所以一般方法无法实现 swap, 需要使用数组或者对象

1.17 命名习惯

类名首字母大写. 其余的, 首字母小写

少用下划线

随写随用,而不是上方统一声明、分开使用


1.18 修饰符

访问控制修饰符

其他修饰符

static

不属于某个实例, 而是属于整个类的(属性). static 变量, 相当于该类一个全局变量, 有点像 C 中的 extern 全局变量, 是所有该类的对象实例所共享的. 这样看来, Java 的类是一个树的结构, 根结点中存储着公有信息, 而对象实例是衍生出来的子结点. 也就是说, static 是一个公共的路灯, 只有一盏, 每个人可以去开关路灯. 但是如果你要去关掉某一户人家里的灯, 就要明确指明他家的门牌号

类就相当于计网中的协议, 比如网络层协议, 规定了每个数据包应该有什么样的格式. 而对象则是一个个具体的实际的数据包.

类变量, 相当于协议头部的一个字段, 所有这个类的对象实例都有相同的头部信息. 相对的, 成员变量则是数据部分.

static 变量多带带划分一块存储空间, 不与具体的对象绑定在一起, 该存储空间被类的各个对象所共享.

static 变量值在方法区加载一次, 而 非 static 变量在创建对象时会加载很多次, 每次创建都会拷贝一份

static 方法再内存中有专用的代码段

static 的访问

static 方法可以访问 static 变量 (类变量)

static 方法不能访问无 static 前缀的 普通成员变量, 不能访问实例变量, 也就是不能使用 thissuper, 调用类方法时, 可以通过 `类名.

普通成员函数 可以访问 static 变量

可以通过 类名.类变量 访问类变量, 也可以通过 对象名.类变量 访问类变量. 同理, 调用类方法时可以用 类名.类方法, 也可以用 类名.类方法

class A{
    static int var = 1;
    public static void main(String args[]){
        A.var++;            // OK, 类名.类变量
        A a = new A();
        a.var++;            // OK, 对象名.类变量
        var++;                // OK, 直接访问
    }
}

final, 不可改变的, 最终的

类前面加上 final, 表示这个类不能被继承, 有利于 Java 的优化

方法前面加上 final, 则这个方法不能被子类覆盖 Override

字段前面加上 final, 能且只能被赋值一次, 然后就不能被改变了. 通常用 static final 表示常量

2. 面向对象, OOP 2.1 类和对象

类 = 字段(成员变量) + 方法(成员函数)

成员变量的生存期 ---> 该对象的生存期, new 开始, GC 收集

成员变量的作用域 ---> 类的内部

构造方法, 构造函数, new 一个新的对象会调用构造方法, 可以重载 overload (参数表不同)

初始化顺序

1.new
2.先跳到构造函数(但不进入)
3.调到父类的构造函数(如果有父类)
4.重复3, 一直到最高的父类
5.跳到构造函数外面的 定义初始化
    int price = 80, balance = 0;
6.进入构造函数, 完成构造函数里面的语句
7.回到子类, 进行子类的定义初始化, 再完成子类的构造函数
8.把构造出来的对象交给对象实例 vm 管理

如果有构造方法的重载, 而且如果其中一个要调用另一个构造方法, 那么要借助 this

class Person{
    private int age, id;
    public Person(){
        this(1);// 必须放在最开始, 调用另外一个构造方法
        age = 0;
    }
    public Person(int pid){
        id = pid;
    }
}

析构函数使用的是 finalize() 方法, 但是一般不用去定义, 交给 JVM 就好了

对象是实体, 可以像理解 C++ 的指针一样理解对象实例

必须 new, 才会分配具体的空间, 每个对象的 id 不同

如果是用另一个对象对其赋值, 则相当于两个人管理同一个对象实例, 和指针一样

Student s1 = new Student();
Student s2 = s1;
s1.setAge(5);   // 5
s1.getAge();    // 5
s2.setAge(10);  // s2 更新 age
s1.getAge();    // 10, s1也会修改, 因为两者指向同一块区域

安全性

一个对象实例是内存中的一块区域, 只能通过同类型的引用去访问, 不能随便拿一个指针乱指到一个实例(内存区域)

2.2 访问控制

private

是对类的限制, 而不是对对象的限制

同一个类的内部, 该类的不同对象实例之间, 可以互相访问private.

但是出了这个类,就无法访问private了。举例如下

class Lower{
    private int val = 0;

    public void test(){
        Lower a = new Lower();
        Lower b = new Lower();
        // 类的内部, 该类的不同对象实例之间, 可以互相访问private
        a.val = b.val;
    }
}

class Higher{
    public void test2(){
        Lower l1 = new Lower();
        Lower l2 = new Lower();
        // error, not visible. 超出了Lower类的内部, private字段就变成了不可见
        l1.val = l2.val;
    }
}

private 方法和字段不能继承

public

default (friendly)

既没有前缀 public, 也没有前缀 private, 那么这个成员是 default

那么和它位于同一个包(同一个文件夹)的其他类可以访问.

注意, 不需要显式声明为 default

protected

同一包内的类可见

所有子类可见

继承关系

父类 public, 子类也必须为 public

父类 protected, 子类 protected, public, private

父类 private 不能够被继承

2.3 重载

方法重载: 多个方法有着相同的名字, 这些方法的签名 signature 不同 (参数不同, 或者参数类型不同), 编译的时候能够被识别出来

通过方法重载, 可以实现多态

2.4 封装

模块化, 把相关的属性和方法封装成为一个类

信息隐蔽, 隐藏类的细节(private), 用户只能通过受保护的接口访问某个类

class Person{
    private int age;
    public int getAge(){
        return age;
    }
}

2.5 继承

父类(super)和子类(sub, 也作派生类)之间如果有共同的属性和方法, 就不用再写第二遍了。可以更好地抽象和分类, 提高代码的可重用性, 提高可维护性

单继承, 一个类只能有一个直接父类, 子类自动继承父类的状态和行为

继承的例子 (extends)

class Person{
    int age;
    String name;
}

// 注意关键字 extends 表示继承(扩展)
class Student extends Person{
    String school;
}

// 如果没有 extends xxx, 那么默认为 extends java.lang.Object 的子类
// 因此所有的类都是直接或间接地继承了 Object

覆盖

JDK 1.5 之后引入了 @Override, 表示覆盖 (修改) 了父类的方法.

可以当做注释, 同时编译器会帮你检查, 如果父类中没有相同的 方法名 + 参数表, 就会报错

父类方法 func() 被覆盖后, 仍然可以用 super.func() 调用父类的方法

重载

方法名相同, 参数表不同. 重载是新的方法.

构造方法是不能继承的, 因为构造方法是和类名同名的

子类构造的过程中需要用 super 来调用父类的构造方法

例题, 问以下代码的结果是什么

class Person {
    String name = "";
    public Person(String n) {
        name = n;
    }
}
class Employee extends Person {
    String empID = "";
    public Employee(String id) {
        empID = id;
    }
}
public class Test {
    public static void main(String args[]) {
        Employee e = new Employee("123");
        System.out.println(e.empID);
    }
}

结果是编译报错, 因为父类 Person 没有无参数的构造函数, 解决方法

// 方法1, 给父类 Person 增加无参数的构造函数(子类会默认调用)
class Person {
    public Person() {}
}

// 方法2, 子类构造函数中用 super 显式调用父类已有的构造函数
class Employee extends Person {
    public Employee(String id) {
        super("Bob");// 注意 super 必须放在第一句
        empID = id;
    }
}

子类对象和父类对象的转换

Student 是一个 Person (子类对象可以被视为父类对象)

Person 不一定是 Student, 具体情况看下面的例子

// 假设 Student extends Person
Person p1 = new Student(); // 编译正常, 运行正常
Student s1 = (Student) p1; // 编译正常, 运行正常

Person p2 = new Person();
Student s2 = (Student) p2;
s2.xxx(); // 【编译正常, 运行错误】

2.6 包

与类的继承没有关系, 子类和父类可以位于不同的包中

相当于名字空间, 解决同名冲突. 同时包也相同于文件夹(存储路径)

另外就是可访问性, 同一个包中的各个类, 默认是可以互相访问的


2.7 抽象(abstract) 和接口(interface)

abstract, 抽象

abstract class Person{
    // 含有抽象方法的类必须声明为抽象类
    // 注意抽象方法是分号;结尾, 而不是花括号
    // 也就是说抽象方法只有声明, 没有实现
    abstract void speak();

    void eat() {
        // 抽象类可以有非抽象方法
    }
}

class Student extends Person{
    @Override
    void speak() {
        // 子类 extends 父类后
        // 要么仍然保持 abstract 方法
        // 要么 Override 覆盖(这里也可以称为实现)父类的 abstract 方法
    }
}

public class Main{
    public static void main(String args[]) {
        // 错误, 抽象类不能被实例化 `instantiate`
        // Person p1 = new Person();

        // 但是抽象类可以用于定义变量
        Person p2 = new Student();
    }
}

interface, 接口, 约定某种特征

interface 是纯抽象类, 所有方法都是 abstract, 也就是 C++ 中的纯虚类

所有的成员变量都是 public static final (相当于 const 常量)

static 表明它属于这个类而不是某个具体对象, final 表明它一旦初始化就不会被改变, 是一个编译时刻已经确定的常量

// 注意直接用 interface 修饰, 不需要 class
interface Flyable{
    // 接口类的所有方法都是 `public abstract`, 不需要显式写出
    // public abstract void fly();

    void fly();
}

interface Runnable{
    // 如果使用 static 修饰符, 则表明这是默认实现, 不需要每次 implements 都去实现 run
    // java8 以上的新特性, 但是这就又回到父子继承了
    static void run() {
    }
}

// implements 多个接口用逗号分隔
class Superman extends Person implements Flyable, Runnable{
    @Override
    public void fly() {
    }
}

class Airplane implements Flyable{
    @Override
    public void fly() {
    }
}

接口可以继承接口,但是不能继承(extends)类

接口不能实现接口,只有类能够实现(implements)接口. 一个类可以实现(implements)多个接口(多继承), 也就是说, 通过接口可以实现不相关类的相同行为(fly()), 而不需要考虑层次关系(``)

引用类型一共有三大类: 1.类 class, 2.接口 interface, 3.数组

2.8 多态, polymorphism

相同的名字表示不同的含义

case1, 编译时多态, 静态

重载 Overload, 多个方法同名但参数表不同

p.say();
p.say("Hi");

case2, 运行时多态, 动态

覆盖 Override, 子类方法覆盖父类同名方法. 动态绑定 dynamic binding, 也称为虚方法调用, 运行的时候根据实例对象来调用方法, 举例如下

class Person{
    void say(){
        System.out.println("hi");
    }
}

class Student extends Person{
    @Override
    void say(){
        System.out.println("hi, I"m a student");
    }
}

public class Main{
    static void func(Person p){
        p.say();
    }

    public static void main(String args[]) {
        Person p = new Person();
        Student s = new Student();
        Person ps = new Student();
        // func() 的参数表说明了我们需要一个 Person 对象
        func(p);
        // 但是我们也可以把 Student 传进去
        // 这时候不会报错, 而且会正确调用子类的 say()
        func(s);
        // 更进一步, 如果我们用向上造型, func() 能接受 ps, 且会正确调用子类的 say()
        func(ps);
    }
}

可以被 Override 的方法都可以称作虚方法, 虚方法不需要特殊的声明

static、final、private 修饰的所有方法都是虚方法

向上造型 upcasting

父类 obj = new 子类();

子类的对象, 可以被当成父类的对象来使用, 可以赋值给父类的变量, 可以传递给需要父类对象的函数, 如果一个容器存放的是父类对象, 那么子类对象也可以放进去

// 为什么? 因为继承了父类, 对外的接口是一样的

子类的对象可以赋值给父类的变量. 注意, Java 不存在 对象对象 的赋值, 而是让两个管理员共同管理一个对象. 类比指针, 不是复制内容, 而是给地址.

2.9 OOP 设计思想

有哪些类, 类里面有什么属性和方法, 类之间的关系(继承, 关联), 对象之间发送消息(调用方法)

3. 容器 3.1 什么是容器

容器 container, 是放东西的东西, 数组可以看做一种容器, 但是数组的长度一旦确定就无法改变, 而容器一般可以改变其容量


基本数据类型数组对象数组

// 基本数据类型数组, 每一个元素都是基本数据类型
int[] ai = new int[32]; // 每个元素被初始化为0

// String[] 数组, 对象数组, 每一个元素只是一个管理者, 一个指针, 而不是保存实际内容
// 元素初始化为 null, 实际内容还不存在, 需要 for 循环去创建和赋值(指向)
String[] as = new String[10];

3.2 顺序容器 ArrayList

容器类

// import java.util.ArrayList;
ArrayList noteList = new ArrayList();

// 用法参考 https://www.w3schools.com/java/java_arraylist.asp
noteList.add( Integer.toString(0) );
noteList.add( "1" );
noteList.get(0);
noteList.set(0, "00");

// import java.util.Collections;
// 排序
Collections.sort(noteList);

noteList.remove(0);
noteList.clear();

// 如果要构建一个数组, 可以调用 toArray() 方法
int size = noteList.size();
String[] mylist = new String[size];
noteList.toArray(mylist);

关系图

3.3 Set

去重

HashSet s = new HashSet();
s.add("first");
s.add("second");
s.add("first");
sysout(s); // [first, second]
s.contains("1"); // false

参考文档

https://docs.oracle.com/javas...

https://www.tutorialspoint.co...

3.4 Map

键值映射关系

/*
映射关系
1        penny
5        nickel
10        dime
25        quarter
50        half-dollar
*/
HashMap dollarMap = new HashMap();
dollarMap.put(1, "penny"); // 注意其他容器都是 add, map 是 put
dollarMap.put(5, "nickel");
dollarMap.put(10, "dime");
dollarMap.put(25, "quarter");
dollarMap.put(50, "half");
dollarMap.replace(50, "half-dollar");
dollarMap.containsKey(30); // false
dollarMap.get(30); // null
dollarMap.get(50);

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/74354.html

相关文章

  • java&javaweb学习笔记(汇总)

    摘要:我的学习笔记汇总标签笔记分为两大部分和笔记内容主要是对一些基础特性和编程细节进行总结整理,适合了解基础语法,想进一步深入学习的人如果觉得不错,请给,这也是对我的鼓励,有什么意见欢迎留言反馈目录基础巩固笔记反射基础巩固笔记泛型基础巩 我的java&javaweb学习笔记(汇总) 标签: java [TOC] 笔记分为两大部分:javase和javaweb javase javawe...

    yagami 评论0 收藏0
  • Java初学者最佳的学习方法以及会遇到的坑(内含学习资料)!

    摘要:最近系统整理了一套初学者最佳的学习方法以及会遇到的坑等,希望对你有所帮助。正常的智商其实,学习并不需要所谓的数学逻辑好,需要英语水平棒。大周期每天学习时间五个小时以上的,建议学习周期。三学习时会遇到的坑不知道学习的重点,下面学习路线会画。 最近系统整理了一套java初学者最佳的学习方法以及会遇到的坑等,希望对你有所帮助。 目录: 一、学习java的前提 二、学习java的方法 三、学习...

    Half 评论0 收藏0
  • Java入门请不要放弃,学习路线以及侧重点分析

    摘要:而面向搜索引擎,就是我们要及时的使用百度谷歌遇到问题无法解决,先别急着放弃,可以去网络寻找答案,你的坑大部分别人都已经走过了,大部分都可以找到合适的解决方案。 showImg(https://segmentfault.com/img/remote/1460000019236352?w=866&h=456); 前言: ●众多的语言,到底哪一门才是适合我的?●我们为什么要学习Java语言呢...

    mochixuan 评论0 收藏0
  • ApacheCN 编程/大数据/数据科学/人工智能学习资源 2019.6

    摘要:请回复这个帖子并注明组织个人信息来申请加入。权限分配灵活,能者居之。数量超过个,在所有组织中排名前。网站日超过,排名的峰值为。导航归档社区自媒体平台微博知乎专栏公众号博客园简书合作侵权,请联系请抄送一份到赞助我们 Special Sponsors showImg(https://segmentfault.com/img/remote/1460000018907426?w=1760&h=...

    Bmob 评论0 收藏0
  • ApacheCN 编程/大数据/数据科学/人工智能学习资源 2019.5

    摘要:请回复这个帖子并注明组织个人信息来申请加入。版笔记等到中文字幕翻译完毕后再整理。数量超过个,在所有组织中排名前。网站日超过,排名的峰值为。主页归档社区自媒体平台微博知乎专栏公众号博客园简书合作侵权,请联系请抄送一份到赞助我们 Special Sponsors showImg(https://segmentfault.com/img/remote/1460000018907426?w=1...

    zhonghanwen 评论0 收藏0

发表评论

0条评论

tianlai

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<