学习路线

本文是Java高级编程精华笔记,是对菜鸟教程中Java面向对象和Java高级编程的重要章节进行了学习,整理形成的学习笔记,知识图谱如下图所示:

002-Java高级编程精华笔记 - 图1

如果想对Java深入学习,可以参考阿里巴巴的技术图谱

https://developer.aliyun.com/graph/java

002-Java高级编程精华笔记 - 图2

继承

Java使用extends关键字来声明继承:

  1. class 父类 {
  2. }
  3. class 子类 extends 父类 {
  4. }

示例,子类企鹅和子类老鼠继承父类动物:

  1. //父类:动物
  2. public class Animal {
  3. private String name;
  4. private int id;
  5. public Animal(String myName, int myid) {
  6. name = myName;
  7. id = myid;
  8. }
  9. public void eat() {
  10. System.out.println(name + "正在吃");
  11. }
  12. public void sleep() {
  13. System.out.println(name + "正在睡");
  14. }
  15. public void introduction() {
  16. System.out.println("大家好!我是" + id + "号" + name + ".");
  17. }
  18. }
  1. //子类:企鹅
  2. public class Penguin extends Animal {
  3. public Penguin(String myName, int myid) {
  4. super(myName, myid);
  5. }
  6. }
  1. //子类:老鼠
  2. public class Mouse extends Animal {
  3. public Mouse(String myName, int myid) {
  4. super(myName, myid);
  5. }
  6. }

Java只支持单继承,不支持多继承,但可以多重继承:

002-Java高级编程精华笔记 - 图3

  • 子类会继承父类的非private属性、方法。
  • 子类可以扩展自己的属性、方法。
  • 子类可以覆盖父类的方法,用自己的方式实现。

也就是,你的是我的,我的还是我的,我还可以改变你的

  • 构造器,子类不会继承父类,而且如果父类的构造器有参数,子类必须通过super关键字显式调用。

也就是,你老子始终是你老子

implements关键字

前面说到了Java使用extends声明继承类,而implements用来声明实现接口,并且可以同时实现多个接口。

  1. public interface A {
  2. public void eat();
  3. public void sleep();
  4. }
  5. public interface B {
  6. public void show();
  7. }
  8. public class C implements A,B {
  9. }

super和this关键字

super:用来实现对父类成员的访问。

this:指向自己的引用。

示例:

  1. class Animal {
  2. void eat() {
  3. System.out.println("animal : eat");
  4. }
  5. }
  6. class Dog extends Animal {
  7. void eat() {
  8. System.out.println("dog : eat");
  9. }
  10. void eatTest() {
  11. this.eat(); // this 调用自己的方法
  12. super.eat(); // super 调用父类方法
  13. }
  14. }
  15. public class Test {
  16. public static void main(String[] args) {
  17. Animal a = new Animal();
  18. a.eat();
  19. Dog d = new Dog();
  20. d.eatTest();
  21. }
  22. }

final关键字

如果修饰类,则表示类不能被继承。如果修饰方法,则表示方法不能被子类重写。

重写与重载

重写与重载的区别可以通过下面这张图来看:

002-Java高级编程精华笔记 - 图4

重写就是子类覆盖父类,方法名和参数都一样:

002-Java高级编程精华笔记 - 图5

重载就是在一个类里面的多个方法,方法名相同,参数不同。调用时根据入参匹配到不同的方法:

002-Java高级编程精华笔记 - 图6

多态

多态是同一个行为具有多个不同表现形式或形态的能力。重写可以看做是父类和子类之间多态性的一种表现(重载可以理解成多态的具体表现形式),如图所示:

002-Java高级编程精华笔记 - 图7

  1. class Shape {
  2. void draw() {}
  3. }
  4. class Circle extends Shape {
  5. void draw() {
  6. System.out.println("Circle.draw()");
  7. }
  8. }
  9. class Square extends Shape {
  10. void draw() {
  11. System.out.println("Square.draw()");
  12. }
  13. }
  14. class Triangle extends Shape {
  15. void draw() {
  16. System.out.println("Triangle.draw()");
  17. }
  18. }

多态存在有三个必要条件:

  • 继承
  • 重写
  • 父类引用指向子类对象:Parent p = new Child();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,再去调用子类的同名方法。

多态有三种实现方式:

  1. 重写
  2. 接口
  3. 抽象类和抽象方法

抽象类

抽象类更普通类的区别在于,它不能实例化对象,只能被继承使用。抽象类使用abstract关键字定义:

  1. public abstract class Employee
  2. {
  3. private String name;
  4. private String address;
  5. private int number;
  6. public Employee(String name, String address, int number)
  7. {
  8. System.out.println("Constructing an Employee");
  9. this.name = name;
  10. this.address = address;
  11. this.number = number;
  12. }
  13. public double computePay()
  14. {
  15. System.out.println("Inside Employee computePay");
  16. return 0.0;
  17. }
  18. public void mailCheck()
  19. {
  20. System.out.println("Mailing a check to " + this.name
  21. + " " + this.address);
  22. }
  23. public String toString()
  24. {
  25. return name + " " + address + " " + number;
  26. }
  27. public String getName()
  28. {
  29. return name;
  30. }
  31. public String getAddress()
  32. {
  33. return address;
  34. }
  35. public void setAddress(String newAddress)
  36. {
  37. address = newAddress;
  38. }
  39. public int getNumber()
  40. {
  41. return number;
  42. }
  43. }

抽象方法

抽象类里面既可以定义普通方法,也可以定义抽象方法:

  1. public abstract class Employee
  2. {
  3. private String name;
  4. private String address;
  5. private int number;
  6. public abstract double computePay();
  7. }

抽象方法也是通过abstract关键字定义,只有方法名,没有方法体(方法名后面是分号而不是花括号),具体实现由它的子类确定。

抽象方法最终必须被重写了才能在实例化对象中使用。如果一个类继承了带有抽象方法的抽象类,那么这个类要么也是抽象类,要么就必须重写抽象方法。

接口

接口不是类,它们属于不同的概念。接口通过interface关键字来定义:

  1. public interface Animal {
  2. public void eat();
  3. public void travel();
  4. }
  • 接口和接口中的方法是隐式抽象的,不必使用abstract关键字。
  • 接口中的方法都是public

类使用implements关键字实现接口:

  1. public class MammalInt implements Animal{
  2. public void eat(){
  3. System.out.println("Mammal eats");
  4. }
  5. public void travel(){
  6. System.out.println("Mammal travels");
  7. }
  8. public int noOfLegs(){
  9. return 0;
  10. }
  11. public static void main(String args[]){
  12. MammalInt m = new MammalInt();
  13. m.eat();
  14. m.travel();
  15. }
  16. }

类必须实现接口里面的所有方法,否则会编译失败。只有抽象类才可以不实现接口的方法。

一个接口能继承另一个接口,接口的继承也是使用extends关键字:

  1. // 文件名: Sports.java
  2. public interface Sports
  3. {
  4. public void setHomeTeam(String name);
  5. public void setVisitingTeam(String name);
  6. }
  7. // 文件名: Football.java
  8. public interface Football extends Sports
  9. {
  10. public void homeTeamScored(int points);
  11. public void visitingTeamScored(int points);
  12. public void endOfQuarter(int quarter);
  13. }
  14. // 文件名: Hockey.java
  15. public interface Hockey extends Sports
  16. {
  17. public void homeGoalScored();
  18. public void visitingGoalScored();
  19. public void endOfPeriod(int period);
  20. public void overtimePeriod(int ot);
  21. }

并且接口支持多继承:

  1. public interface Hockey extends Sports, Event

实现了子接口的类,需要同时实现所有父接口中的方法。

接口里面也可以没有方法:

  1. package java.util;
  2. public interface EventListener
  3. {}

它的主要目的是:

  1. 建立一个公共的父接口。
  2. 让实现它的类属于一个特定的类型。

枚举

枚举是一种特殊的类,一般用来表示一组常量。枚举使用enum关键字来定义,常量使用逗号,分隔:

  1. enum Color
  2. {
  3. RED, GREEN, BLUE;
  4. }
  5. public class Test
  6. {
  7. // 执行输出结果
  8. public static void main(String[] args)
  9. {
  10. Color c1 = Color.RED;
  11. System.out.println(c1);
  12. }
  13. }

枚举也可以声明在内部类中:

  1. public class Test
  2. {
  3. enum Color
  4. {
  5. RED, GREEN, BLUE;
  6. }
  7. // 执行输出结果
  8. public static void main(String[] args)
  9. {
  10. Color c1 = Color.RED;
  11. System.out.println(c1);
  12. }
  13. }

枚举可以使用for语句遍历:

  1. enum Color
  2. {
  3. RED, GREEN, BLUE;
  4. }
  5. public class MyClass {
  6. public static void main(String[] args) {
  7. for (Color myVar : Color.values()) {
  8. System.out.println(myVar);
  9. }
  10. }
  11. }

也可以用在switch语句中:

  1. enum Color
  2. {
  3. RED, GREEN, BLUE;
  4. }
  5. public class MyClass {
  6. public static void main(String[] args) {
  7. Color myVar = Color.BLUE;
  8. switch(myVar) {
  9. case RED:
  10. System.out.println("红色");
  11. break;
  12. case GREEN:
  13. System.out.println("绿色");
  14. break;
  15. case BLUE:
  16. System.out.println("蓝色");
  17. break;
  18. }
  19. }
  20. }

enum定义的枚举默认继承了java.lang.Enum类,具有3个方法:

  • values(),返回枚举中所有常量。
  • ordinal(),返回常量的索引。
  • valueOf(),返回指定字符串值的常量。
  1. enum Color
  2. {
  3. RED, GREEN, BLUE;
  4. }
  5. public class Test
  6. {
  7. public static void main(String[] args)
  8. {
  9. // 调用 values()
  10. Color[] arr = Color.values();
  11. // 迭代枚举
  12. for (Color col : arr)
  13. {
  14. // 查看索引
  15. System.out.println(col + " at index " + col.ordinal());
  16. }
  17. // 使用 valueOf() 返回枚举常量,不存在的会报错 IllegalArgumentException
  18. System.out.println(Color.valueOf("RED"));
  19. }
  20. }

枚举跟普通类一样可以定义变量、方法和构造函数:

  1. enum Color
  2. {
  3. RED, GREEN, BLUE;
  4. // 构造函数
  5. private Color()
  6. {
  7. System.out.println("Constructor called for : " + this.toString());
  8. }
  9. public void colorInfo()
  10. {
  11. System.out.println("Universal Color");
  12. }
  13. }
  14. public class Test
  15. {
  16. // 输出
  17. public static void main(String[] args)
  18. {
  19. Color c1 = Color.RED;
  20. System.out.println(c1);
  21. c1.colorInfo();
  22. }
  23. }

输出:

  1. Constructor called for : RED
  2. Constructor called for : GREEN
  3. Constructor called for : BLUE
  4. RED
  5. Universal Color

包可以理解为类的目录,使用package关键字定义:

  1. package com.runoob;
  2. public class Runoob {
  3. }

一个公司一般使用它互联网域名的倒序形式来作为它的包名,比如runoob.com,所有的包名都以com.runoob开头。

同一个包中的类可以直接访问,而访问不同的包需要先import。

  1. //导入包下所有类
  2. import payroll.*;
  3. //导入包下某个类
  4. import payroll.Employee;

集合

002-Java高级编程精华笔记 - 图8

集合(Collections)和数组(Arrays)的区别:

  • 长度区别:数组固定;集合可变。
  • 内容区别:数组既可以是基本类型,也可以是引用类型;集合只能是引用类型。
  • 存储类型:数组只能存储一种类型;集合可以存储不同类型(但一般也只存储一种类型)

集合中只能使用基本类型的包装类:

002-Java高级编程精华笔记 - 图9

集合主要包括两种类型的容器:Collection和Map,Collection是元素集合,Map是键值对。

集合有3个层次:

002-Java高级编程精华笔记 - 图10

接口代表集合的抽象数据类型,我们重点关注实现类和算法,尤其是4种常用实现类:ArrayList、LinkedList、HashSet、HashMap。

ArrayList

ArrayList相当于可以动态修改的数组。它继承了AbstractList,并实现了List接口:

002-Java高级编程精华笔记 - 图11

定义

  1. import java.util.ArrayList; // 引入 ArrayList 类
  2. ArrayList<E> objectName = new ArrayList<>();  // 初始化

添加元素

使用add()方法:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. System.out.println(sites);
  10. }
  11. }

访问元素

使用get()方法:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. System.out.println(sites.get(1)); // 访问第二个元素
  10. }
  11. }

修改元素

使用set()方法:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. sites.set(2, "Wiki"); // 第一个参数为索引位置,第二个为要修改的值
  10. System.out.println(sites);
  11. }
  12. }

删除元素

使用remove()方法:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. sites.remove(3); // 删除第四个元素
  10. System.out.println(sites);
  11. }
  12. }

计算大小

使用size()方法:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. System.out.println(sites.size());
  10. }
  11. }

迭代遍历

for循环:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. for (int i = 0; i < sites.size(); i++) {
  10. System.out.println(sites.get(i));
  11. }
  12. }
  13. }

for-each语句:

  1. import java.util.ArrayList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. ArrayList<String> sites = new ArrayList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. for (String i : sites) {
  10. System.out.println(i);
  11. }
  12. }
  13. }

排序

使用Collections.sort()方法:

  1. import java.util.ArrayList;
  2. import java.util.Collections; // 引入 Collections 类
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. ArrayList<String> sites = new ArrayList<String>();
  6. sites.add("Taobao");
  7. sites.add("Wiki");
  8. sites.add("Runoob");
  9. sites.add("Weibo");
  10. sites.add("Google");
  11. Collections.sort(sites); // 字母排序
  12. for (String i : sites) {
  13. System.out.println(i);
  14. }
  15. }
  16. }

LinkedList

LinkedList是链表,分为单向链表和双向链表。

单向链表包含2个值,①当前节点的值,②下一个节点的链接:

002-Java高级编程精华笔记 - 图12

双向链表包含3个值,①当前节点的值,②向前的节点链接,③向后的节点链接:

002-Java高级编程精华笔记 - 图13

与ArrayList相比,LinkedList的增加和删除的效率更高,而修改和查找的效率更低。

快速记忆法:

增删:LinkedList

改查:ArrayList

LinkedList继承了AbstractSequentialList,实现了很多接口:

002-Java高级编程精华笔记 - 图14

定义

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. LinkedList<E> list = new LinkedList<E>(); // 普通创建方法
  4. 或者
  5. LinkedList<E> list = new LinkedList(Collection<? extends E> c); // 使用集合创建链表

添加元素

  1. import java.util.LinkedList;
  2. public class RunoobTest {
  3. public static void main(String[] args) {
  4. LinkedList<String> sites = new LinkedList<String>();
  5. sites.add("Google");
  6. sites.add("Runoob");
  7. sites.add("Taobao");
  8. sites.add("Weibo");
  9. System.out.println(sites);
  10. }
  11. }

在列表开头添加元素

使用addFirst()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. // 使用 addFirst() 在头部添加元素
  10. sites.addFirst("Wiki");
  11. System.out.println(sites);
  12. }
  13. }

在列表结尾添加元素

使用addLast()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. // 使用 addLast() 在尾部添加元素
  10. sites.addLast("Wiki");
  11. System.out.println(sites);
  12. }
  13. }

在列表开头移除元素

使用removeFirst()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. // 使用 removeFirst() 移除头部元素
  11. sites.removeFirst();
  12. System.out.println(sites);
  13. }
  14. }

在列表结果移除元素

使用removeLast()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. // 使用 removeLast() 移除尾部元素
  11. sites.removeLast();
  12. System.out.println(sites);
  13. }
  14. }

获取列表开头的元素

使用getFirst()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. // 使用 getFirst() 获取头部元素
  11. System.out.println(sites.getFirst());
  12. }
  13. }

获取列表结尾的元素

使用getLast()方法:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. // 使用 getLast() 获取尾部元素
  11. System.out.println(sites.getLast());
  12. }
  13. }

迭代元素

可以使用for循环:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. for (int size = sites.size(), i = 0; i < size; i++) {
  11. System.out.println(sites.get(i));
  12. }
  13. }
  14. }

也可以使用for-each语句:

  1. // 引入 LinkedList 类
  2. import java.util.LinkedList;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. LinkedList<String> sites = new LinkedList<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Weibo");
  10. for (String i : sites) {
  11. System.out.println(i);
  12. }
  13. }
  14. }

HashMap

HashMap叫做哈希表,相当于键值对(key-value)的字典。它继承于AbstractMap,实现了Map、Cloneable、java.io.Serializable接口:

002-Java高级编程精华笔记 - 图15

定义

  1. import java.util.HashMap; // 引入 HashMap 类
  2. HashMap<Integer, String> Sites = new HashMap<>();

HashMap中只能使用基本类型的包装类,因为HashMap也是集合一种,在集合中只能使用包装类。

添加元素

使用put()方法:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. System.out.println(Sites);
  13. }
  14. }

访问元素

使用get()方法:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. System.out.println(Sites.get(3));
  13. }
  14. }

删除元素

使用remove()方法:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. Sites.remove(4);
  13. System.out.println(Sites);
  14. }
  15. }

删除所有键值对

使用clear()方法:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. Sites.clear();
  13. System.out.println(Sites);
  14. }
  15. }

计算大小

使用size()方法:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. System.out.println(Sites.size());
  13. }
  14. }

迭代

推荐使用entrySet:

  1. Map<Integer, Integer> map = new HashMap<Integer, Integer>();
  2. for(Map.Entry<Integer, Integer> entry : map.entrySet()){
  3. System.out.println("key = " + entry.getKey() + ", value = " + entry.getValue())
  4. }

也可以用其他方式:

  1. // 引入 HashMap 类
  2. import java.util.HashMap;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. // 创建 HashMap 对象 Sites
  6. HashMap<Integer, String> Sites = new HashMap<Integer, String>();
  7. // 添加键值对
  8. Sites.put(1, "Google");
  9. Sites.put(2, "Runoob");
  10. Sites.put(3, "Taobao");
  11. Sites.put(4, "Zhihu");
  12. // 输出 key 和 value
  13. for (Integer i : Sites.keySet()) {
  14. System.out.println("key: " + i + " value: " + Sites.get(i));
  15. }
  16. // 返回所有 value 值
  17. for(String value: Sites.values()) {
  18. // 输出每一个value
  19. System.out.print(value + ", ");
  20. }
  21. }
  22. }

HashSet

HashSet是一个不允许有重复元素的集合。它实现了Set接口:

002-Java高级编程精华笔记 - 图16

定义

  1. import java.util.HashSet; // 引入 HashSet 类
  2. HashSet<String> sites = new HashSet<String>();

添加元素

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. System.out.println(sites);
  12. }
  13. }

判断元素是否存在

使用contains()方法:

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. System.out.println(sites.contains("Taobao"));
  12. }
  13. }

删除元素

使用remove()方法:

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. sites.remove("Taobao"); // 删除元素,删除成功返回 true,否则为 false
  12. System.out.println(sites);
  13. }
  14. }

删除所有元素

使用clear()方法:

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. sites.clear();
  12. System.out.println(sites);
  13. }
  14. }

计算大小

使用size()方法:

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. System.out.println(sites.size());
  12. }
  13. }

迭代

使用for-each语句:

  1. // 引入 HashSet 类
  2. import java.util.HashSet;
  3. public class RunoobTest {
  4. public static void main(String[] args) {
  5. HashSet<String> sites = new HashSet<String>();
  6. sites.add("Google");
  7. sites.add("Runoob");
  8. sites.add("Taobao");
  9. sites.add("Zhihu");
  10. sites.add("Runoob"); // 重复的元素不会被添加
  11. for (String i : sites) {
  12. System.out.println(i);
  13. }
  14. }
  15. }

Iterator

Iterator是迭代器,可以用来迭代ArrayList等集合。迭代器主要有3个方法:

  • next():返回下一个元素,并更新迭代器状态。
  • hasNext():检查是否还有元素。
  • remove():删除元素。

获取集合的迭代器

  1. // 引入 ArrayList 和 Iterator 类
  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. public class RunoobTest {
  5. public static void main(String[] args) {
  6. // 创建集合
  7. ArrayList<String> sites = new ArrayList<String>();
  8. sites.add("Google");
  9. sites.add("Runoob");
  10. sites.add("Taobao");
  11. sites.add("Zhihu");
  12. // 获取迭代器
  13. Iterator<String> it = sites.iterator();
  14. // 输出集合中的第一个元素
  15. System.out.println(it.next());
  16. }
  17. }

迭代器遍历集合

  1. // 引入 ArrayList 和 Iterator 类
  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. public class RunoobTest {
  5. public static void main(String[] args) {
  6. // 创建集合
  7. ArrayList<String> sites = new ArrayList<String>();
  8. sites.add("Google");
  9. sites.add("Runoob");
  10. sites.add("Taobao");
  11. sites.add("Zhihu");
  12. // 获取迭代器
  13. Iterator<String> it = sites.iterator();
  14. // 输出集合中的所有元素
  15. while(it.hasNext()) {
  16. System.out.println(it.next());
  17. }
  18. }
  19. }

删除元素

  1. // 引入 ArrayList 和 Iterator 类
  2. import java.util.ArrayList;
  3. import java.util.Iterator;
  4. public class RunoobTest {
  5. public static void main(String[] args) {
  6. ArrayList<Integer> numbers = new ArrayList<Integer>();
  7. numbers.add(12);
  8. numbers.add(8);
  9. numbers.add(2);
  10. numbers.add(23);
  11. Iterator<Integer> it = numbers.iterator();
  12. while(it.hasNext()) {
  13. Integer i = it.next();
  14. if(i < 10) {
  15. it.remove(); // 删除小于 10 的元素
  16. }
  17. }
  18. System.out.println(numbers);
  19. }
  20. }

泛型

泛型可以理解为通用类型,不是具体某个类型,而是泛指某些类型。

Java中的泛型标记符如下所示:

  • E - Element (在集合中使用,因为集合中存放的是元素)
  • T - Type(Java 类)
  • K - Key(键)
  • V - Value(值)
  • N - Number(数值类型)
  • - 表示不确定的 java 类型

示例:

  1. public class GenericMethodTest {
  2. // 泛型方法 printArray
  3. public static <E> void printArray(E[] inputArray) {
  4. // 输出数组元素
  5. for (E element : inputArray) {
  6. System.out.printf("%s ", element);
  7. }
  8. System.out.println();
  9. }
  10. public static void main(String args[]) {
  11. // 创建不同类型数组: Integer, Double 和 Character
  12. Integer[] intArray = {1, 2, 3, 4, 5};
  13. Double[] doubleArray = {1.1, 2.2, 3.3, 4.4};
  14. Character[] charArray = {'H', 'E', 'L', 'L', 'O'};
  15. System.out.println("整型数组元素为:");
  16. printArray(intArray); // 传递一个整型数组
  17. System.out.println("\n双精度型数组元素为:");
  18. printArray(doubleArray); // 传递一个双精度型数组
  19. System.out.println("\n字符型数组元素为:");
  20. printArray(charArray); // 传递一个字符型数组
  21. }
  22. }

其中<E>放在方法前表明这是一个泛型方法。可以通过extends限制类型的范围:

  1. public class MaximumTest
  2. {
  3. // 比较三个值并返回最大值
  4. //java.lang.Comparable是个接口,包含一个compareTo()方法
  5. public static <T extends Comparable<T>> T maximum(T x, T y, T z)
  6. {
  7. T max = x; // 假设x是初始最大值
  8. if ( y.compareTo( max ) > 0 ){
  9. max = y; //y 更大
  10. }
  11. if ( z.compareTo( max ) > 0 ){
  12. max = z; // 现在 z 更大
  13. }
  14. return max; // 返回最大对象
  15. }
  16. public static void main( String args[] )
  17. {
  18. System.out.printf( "%d, %d 和 %d 中最大的数为 %d\n\n",
  19. 3, 4, 5, maximum( 3, 4, 5 ) );
  20. System.out.printf( "%.1f, %.1f 和 %.1f 中最大的数为 %.1f\n\n",
  21. 6.6, 8.8, 7.7, maximum( 6.6, 8.8, 7.7 ) );
  22. System.out.printf( "%s, %s 和 %s 中最大的数为 %s\n","pear",
  23. "apple", "orange", maximum( "pear", "apple", "orange" ) );
  24. }
  25. }

除了泛型泛型方法,还可以定义泛型类

  1. public class Box<T> {
  2. private T t;
  3. public void add(T t) {
  4. this.t = t;
  5. }
  6. public T get() {
  7. return t;
  8. }
  9. public static void main(String[] args) {
  10. Box<Integer> integerBox = new Box<Integer>();
  11. Box<String> stringBox = new Box<String>();
  12. integerBox.add(new Integer(10));
  13. stringBox.add(new String("菜鸟教程"));
  14. System.out.printf("整型值为 :%d\n\n", integerBox.get());
  15. System.out.printf("字符串为 :%s\n", stringBox.get());
  16. }
  17. }

?是类型通配符,比如List<?>在逻辑上是List<String>List<Integer>等的父类:

  1. import java.util.*;
  2. public class GenericTest {
  3. public static void main(String[] args) {
  4. List<String> name = new ArrayList<String>();
  5. List<Integer> age = new ArrayList<Integer>();
  6. List<Number> number = new ArrayList<Number>();
  7. name.add("icon");
  8. age.add(18);
  9. number.add(314);
  10. getData(name);
  11. getData(age);
  12. getData(number);
  13. }
  14. public static void getData(List<?> data) {
  15. System.out.println("data :" + data.get(0));
  16. }
  17. }

?也可以通过extends关键字来限定类型范围:

  1. import java.util.*;
  2. public class GenericTest {
  3. public static void main(String[] args) {
  4. List<String> name = new ArrayList<String>();
  5. List<Integer> age = new ArrayList<Integer>();
  6. List<Number> number = new ArrayList<Number>();
  7. name.add("icon");
  8. age.add(18);
  9. number.add(314);
  10. //getUperNumber(name);//1
  11. getUperNumber(age);//2
  12. getUperNumber(number);//3
  13. }
  14. public static void getData(List<?> data) {
  15. System.out.println("data :" + data.get(0));
  16. }
  17. //只接受Number及其子类
  18. public static void getUperNumber(List<? extends Number> data) {
  19. System.out.println("data :" + data.get(0));
  20. }
  21. }

List<? extends Number表示只接受Number及其子类(指定上限)。此外还能通过List<? super Number>来表示只能接受Number及其父类(指定下限)。

参考资料:

Java面向对象 https://www.runoob.com/java/java-inheritance.html

Java高级编程 https://www.runoob.com/java/java-data-structures.html

Java集合超详解 https://blog.csdn.net/feiyanaffection/article/details/81394745