抽象类 抽象类是一种不能被实例化的类 ,它的主要目的是为其子类提供公共的模板和基础实现 。抽象类之所以能够提供这些共享方法和字段,是因为它定义了一些基本的结构和行为,而具体实现则由子类去完成。
当我们需要将一些有共同特征的对象进行抽象时,我们可以使用抽象类 。
例如我们需要定义一系列图形类,比如矩形和圆形等,每个图形都具有计算面积和计算周长的方法,但具体实现方法可能不一样。我们可以定义一个抽象类 Shape
来表示这些图形的共同特征,并且提供一些方法的基本实现,具体的类可以继承这个抽象类并提供自己的实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public abstract class Shape { public abstract double getArea () ; public abstract double getPerimeter () ; public void displaySize () { System.out.println("The area of this shape is: " + getArea()); System.out.println("The perimeter of this shape is: " + getPerimeter()); } } public class Circle extends Shape { private double radius; public Circle (double radius) { this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } @Override public double getPerimeter () { return 2 * Math.PI * radius; } } public class Rectangle extends Shape { private double length; private double width; public Rectangle (double length, double width) { this .length = length; this .width = width; } @Override public double getArea () { return length * width; } @Override public double getPerimeter () { return 2 * (length + width); } }
在上面的代码中,Shape
类是一个抽象类,它定义了两个抽象方法 getArea()
和 getPerimeter()
,以及一个基本实现方法 displaySize()
。而在 Circle
和 Rectangle
类中则是实现了这两个抽象方法并提供了它们自己的实现。这样我们就可以在后续使用这些图形时,通过继承 Shape
类来实现方法的复用和代码结构的统一性。
容器 Iterator接口 Iterator接口是用于遍历集合类中的元素 的接口。通过Iterator,我们可以在集合中遍历元素,判断集合中是否还有元素,获取当前位置元素并将游标向下移动等操作。
Iterator接口提供了4个方法,分别是:
boolean hasNext()
:判断集合中是否还有元素,若有元素则返回 true,否则返回 false;
E next()
:返回集合中的下一个元素;
void remove()
:删除集合中上一次返回的元素;
default void forEachRemaining(Consumer<? super E> action)
:默认方法,遍历剩下的所有元素,并对每个元素执行指定操作。
在使用Iterator接口遍历集合时,需要先使用集合对象的 iterator()
方法来获取一个迭代器对象,然后使用该迭代器对象对集合进行遍历 :
1 2 3 4 5 6 7 8 9 10 List<String> list = new ArrayList <>(); list.add("Java" ); list.add("Python" ); list.add("C++" ); Iterator<String> iter = list.iterator(); while (iter.hasNext()) { String item = iter.next(); System.out.println(item); }
这里我们对list集合进行了遍历,首先使用 list.iterator() 方法获取一个迭代器对象,然后使用 while 循环和 hasNext() 方法判断集合中是否还有元素,如果有则使用 next() 方法获取下一个元素并输出。最终输出的结果为:
Collection接口 List List列表是按照一定次序排列的对象集,对象之间有次序关系,可以重复,主要实现类为ArrayList和LinkedList:
1 2 3 4 5 6 7 8 9 10 11 import java.util.*;public class Main { public static void main (String[] args) { Collection c = new ArrayList <>(); c.add(1 ); c.add(2 ); c.add(3 ); System.out.println(c); } }
c的类型定义为Collection:面向接口,便于修改实现类。
ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除 元素。
泛型 :使用类的时候给类提供类型参数,表示只接受特定类型,如下只接受String类型:
1 ArrayList<String> list = new ArrayList <>();
一些简单操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import java.util.ArrayList;public class Main { public static void main (String[] args) { ArrayList<String> list = new ArrayList <>(); list.add("apple" ); list.add("banana" ); list.add("orange" ); System.out.println(list.get(0 )); System.out.println(list.indexOf("orange" )); for (String s : list) { System.out.println(s); } list.set(0 , "grape" ); list.remove(0 ); if (list.isEmpty()) { System.out.println("ArrayList is empty" ); } if (list.contains("orange" )) { System.out.println("The string 'orange' is in the ArrayList" ); } else { System.out.println("The string 'orange' is not in the ArrayList" ); } int size = list.size(); System.out.println("The size of the list is " + size); } }
基本类型
引用类型
boolean
Boolean
byte
Byte
short
Short
int
Integer
long
Long
float
Float
double
Double
char
Character
Set Set集合继承于java.util.Collection
接口,表示不允许出现重复元素的集合 。Set中的元素是没有顺序的。
Set的常用实现类有HashSet、TreeSet和LinkedHashSet 。其中,HashSet底层是基于哈希表实现的;TreeSet底层是基于红黑树结构实现的,可以对元素进行排序 ;LinkedHashSet底层是基于双向链表和哈希表实现的,它可以按照元素插入的顺序进行排序。
HashSet是最常用的Set实现类之一,内部使用哈希表来实现,是无序的,它内部实现是基于哈希表,不会保证元素添加的顺序和输出的顺序一致。HashSet没有保证元素的顺序 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import java.util.HashSet;public class Main { public static void main (String[] args) { HashSet<String> set = new HashSet <String>(); set.add("apple" ); set.add("banana" ); set.add("orange" ); System.out.println("HashSet: " + set); if (set.contains("banana" )) { System.out.println("HashSet contains banana" ); } System.out.println("HashSet size: " + set.size()); set.remove("orange" ); System.out.println("HashSet after removing orange: " + set); set.clear(); System.out.println("HashSet after clearing all elements: " + set); HashSet<Integer> numbers = new HashSet <Integer>(); numbers.add(1 ); numbers.add(2 ); numbers.add(3 ); numbers.add(4 ); numbers.add(5 ); for (int a : numbers){ System.out.println(a); } HashSet<String> set1 = new HashSet <String>(); set1.add("apple" ); set1.add("banana" ); set1.add("orange" ); HashSet<String> set2 = new HashSet <String>(); set2.add("grape" ); set2.add("banana" ); set2.add("pear" ); set1.retainAll(set2); System.out.println("HashSet intersection of set1 and set2: " + set1); } }
需要排序可以考虑使用TreeSet,TreeSet使用红黑树作为存储结构,可以确保元素被排序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 import java.util.TreeSet;public class Main { public static void main (String[] args) { TreeSet<String> treeSet = new TreeSet <String>(); treeSet.add("apple" ); treeSet.add("banana" ); treeSet.add("orange" ); treeSet.add("mango" ); System.out.println("TreeSet: " + treeSet); System.out.println("TreeSet size: " + treeSet.size()); if (treeSet.contains("banana" )) { System.out.println("TreeSet contains banana" ); } String firstElement = treeSet.first(); String lastElement = treeSet.last(); System.out.println("TreeSet first element: " + firstElement); System.out.println("TreeSet last element: " + lastElement); String lowerOrEqualElement = treeSet.floor("orange" ); String higherOrEqualElement = treeSet.ceiling("orange" ); System.out.println("TreeSet lowerOrEqual orange element: " + lowerOrEqualElement); System.out.println("TreeSet higherOrEqual orange element: " + higherOrEqualElement); treeSet.remove("mango" ); System.out.println("TreeSet after removing mango: " + treeSet); treeSet.clear(); System.out.println("TreeSet after clearing all elements: " + treeSet); TreeSet<Integer> numbers = new TreeSet <Integer>(); numbers.add(1 ); numbers.add(2 ); numbers.add(3 ); numbers.add(4 ); numbers.add(5 ); for (int a:numbers){ System.out.println(a); } } }
LinkedHashSet 是通过哈希表+链表实现的,既可以快速访问元素,又保证了插入顺序。因此,在需要元素有序的情况下,推荐使用 LinkedHashSet。当然,在不需要元素有序的情况下,HashSet 的效率是最高的。
Queue Queue根据排队规则来确定对象的顺序,规则为先进先出 ,主要实现类为LinkedList:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 import java.util.*;public class Main { public static void main (String[] args) { Queue queue = new LinkedList <>(); queue.add(1 ); queue.add(2 ); queue.add(3 ); queue.add(4 ); System.out.println(queue); System.out.println(queue.peek()); System.out.println(queue.poll()); System.out.println(queue); } }
栈 vector是list接口的实现类,栈是vector的延伸,对栈进行操作规则为先进后出 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import java.util.*;public class Main { public static void main (String[] args) { Stack stack = new Stack <>(); stack.push(1 ); stack.push(2 ); stack.push(3 ); stack.push(4 ); System.out.println(stack); System.out.println(stack.pop()); System.out.println(stack); System.out.println(stack.peek()); while (!stack.isEmpty()){ System.out.println(stack.pop()); } } }
Stack也可以当做普通列表用,但是就不具备Stack的性质了。
Map接口 Map 接口中键和值一一映射 ,可以通过键来获取值。
给定一个键和一个值,你可以将该值存储在一个 Map 对象。之后,你可以通过键key来访问对应的值value。
一些常用的 Map 接口的实现类有 HashMap、TreeMap 和 LinkedHashMap :
HashMap:HashMap 是基于哈希表实现的 Map,是最常用的 Map 实现之一。
TreeMap:TreeMap 是基于红黑树实现的 Map,它可以保证元素的顺序,通常用于需要自定义排序的场景。
LinkedHashMap:LinkedHashMap 是哈希表和双向链表的组合实现,可以保证元素的插入顺序。
对于HashMap的简单操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.HashMap;import java.util.Map;public class Main { public static void main (String[] args) { Map<String, Integer> hashMap = new HashMap <>(); hashMap.put("apple" , 1 ); hashMap.put("banana" , 2 ); int appleCount = hashMap.get("apple" ); int bananaCount = hashMap.get("banana" ); System.out.println("appleCount: " + appleCount); System.out.println("bananaCount: " + bananaCount); for (Map.Entry<String, Integer> entry : hashMap.entrySet()) { System.out.println("key: " + entry.getKey() + ", value: " + entry.getValue()); } } }
TreeMap 可以保持元素有序,在后面的操作中会方便排序,下面是一个简单实现排序的例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util.*;public class Main { public static void main (String[] args) { String str = "hello world, hello java, hello world, hello python, hello cplusplus" ; String[] words = str.split("\\s+" ); Map<String, Integer> wordCount = new TreeMap <String, Integer>(); for (String word : words) { if (wordCount.containsKey(word)) { wordCount.put(word, wordCount.get(word) + 1 ); } else { wordCount.put(word, 1 ); } } List<Map.Entry<String, Integer>> list = new ArrayList <Map.Entry<String, Integer>>(wordCount.entrySet()); Collections.sort(list, new Comparator <Map.Entry<String, Integer>>() { @Override public int compare (Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { return o1.getValue().compareTo(o2.getValue()); } }); for (Map.Entry<String, Integer> entry : list) { System.out.println(entry.getKey() + ":" + entry.getValue()); } } }
下面是LinkedHashMap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util.LinkedHashMap;import java.util.Map;public class Main { public static void main (String[] args) { Map<String, String> linkedHashMap = new LinkedHashMap <>(10 ); linkedHashMap.put("apple" , "red" ); linkedHashMap.put("banana" , "yellow" ); linkedHashMap.put("orange" , "orange" ); System.out.println("LinkedHashMap: " + linkedHashMap); String color = linkedHashMap.get("apple" ); System.out.println("The color of apple is: " + color); System.out.print("The values in the LinkedHashMap are: " ); for (String value : linkedHashMap.values()) { System.out.print(value + " " ); } System.out.println(); } }
LinkedHashMap和HashMap在实现上最主要的区别在于 LinkedHashMap 它可以保证元素的插入顺序和访问顺序一致 ,即按照元素插入的顺序或者最近访问的顺序(根据构造方法中的参数设置而定)进行访问。
异常处理 所有的异常类是从 java.lang.Exception
类继承的子类。
捕获异常 使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码,使用 try/catch 的语法如下:
1 2 3 4 5 6 7 try { }catch (ExceptionName e1) { }
一个 try 代码块后面可以跟随多个 catch ,跟随多个 catch 代码块的情况就叫多重捕获。
实例:调用数组超出范围:
1 2 3 4 5 6 7 8 9 10 11 12 13 import java.io.*;public class ExcepTest { public static void main (String args[]) { try { int a[] = new int [2 ]; System.out.println("Access element three :" + a[3 ]); }catch (ArrayIndexOutOfBoundsException e){ System.out.println("Exception thrown :" + e); } System.out.println("Out of the block" ); } }
throw和throws关键字 当在Java中处理异常时,可以使用throw
关键字抛出一个具体的异常对象 ,或者使用throws
关键字声明函数可能抛出的异常类型 。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Example { public static void main (String[] args) { try { divide(10 , 0 ); } catch (ArithmeticException e) { System.out.println("发生了除以零的异常!" ); System.out.println(e.getMessage()); } } public static int divide (int dividend, int divisor) throws ArithmeticException { if (divisor == 0 ) { throw new ArithmeticException ("除数不能为零" ); } return dividend / divisor; } }
一个方法可以声明抛出多个异常,多个异常之间用逗号隔开。
自定义异常类 当我们希望在Java中使用自定义的异常类时,我们需要创建一个继承自Exception
或其子类的新异常类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class CustomException extends Exception { public CustomException (String message) { super (message); } } public class Example { public static void main (String[] args) { try { process(); } catch (CustomException e) { System.out.println("捕获到自定义异常!" ); System.out.println(e.getMessage()); } } public static void process () throws CustomException { throw new CustomException ("发生了自定义异常" ); } }
在上面的示例中,我们首先定义了一个名为CustomException
的自定义异常类,它继承自Exception
类。构造函数接受一个字符串参数用于设置异常信息,并通过super
关键字调用父类Exception
的构造函数来设置异常信息。
finally关键字 finally 关键字用来创建在 try 代码块后面执行的代码块。
无论是否发生异常,finally 代码块中的代码总会被执行。
finally 代码块出现在 catch 代码块最后,语法如下:
1 2 3 4 5 6 7 8 9 try { }catch (异常类型1 异常的变量名1 ){ }catch (异常类型2 异常的变量名2 ){ }finally { }
测试题目 员工的工资 假定要为某个公司编写雇员工资支付程序,这个公司有各种类型的雇员(Employee),不同类型的雇员按不同的方式支付工资(都是整数):
(1)经理(Manager)——每月获得一份固定的工资
(2)销售人员(Salesman)——在基本工资的基础上每月还有销售提成
(3)一般工人(Worker)——则按他每月工作的天数计算工资 在Employee中提供方法getSalary(),用于计算每个雇员一个月的工资,并在子类中重写。
Post_AppendCode的main方法中已经构造Employee的三个变量,分别指向Manager、Salesman、Worker的对象,调用getSalary方法,输出三个对象的工资。 要求:编码实现经理、销售人员、一般工人三个类。
方法接口定义
裁判测试程序样例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import java.util.Scanner;public class Main { public static void main (String[] args) { Scanner scan = new Scanner (System.in); int managerSalary = scan.nextInt(); int salemanSalary = scan.nextInt(); int salemanRaise = scan.nextInt(); int workerEveryday = scan.nextInt(); int workerDays = scan.nextInt(); Employee e1 = new Manager (managerSalary); Employee e2 = new Salesman (salemanSalary, salemanRaise); Employee e3 = new Worker (workerEveryday, workerDays); System.out.println(e1.getSalary()); System.out.println(e2.getSalary()); System.out.println(e3.getSalary()); scan.close(); } }
输入描述
经理的月工资 销售人员的基本工资 销售人员的提成 工人的工作天数 工人每天的工资
输出描述
经理的工资 销售人员的工资 工人的工资
输入样例
输出样例
给出代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 import java.util.Scanner;public class Main { public static void main (String[] args) { Scanner scan = new Scanner (System.in); int managerSalary = scan.nextInt(); int salemanSalary = scan.nextInt(); int salemanRaise = scan.nextInt(); int workerEveryday = scan.nextInt(); int workerDays = scan.nextInt(); Employee e1 = new Manager (managerSalary); Employee e2 = new Salesman (salemanSalary, salemanRaise); Employee e3 = new Worker (workerEveryday, workerDays); System.out.println(e1.getSalary()); System.out.println(e2.getSalary()); System.out.println(e3.getSalary()); scan.close(); } } abstract class Employee { abstract public int getSalary () ; } class Manager extends Employee { private int Salary; public Manager (int Salary) { this .Salary=Salary; } public int getSalary () { return this .Salary; } } class Salesman extends Employee { private int Salary; private int Salarymore; public Salesman (int Salary,int Salarymore) { this .Salary=Salary; this .Salarymore=Salarymore; } public int getSalary () { return this .Salary+Salarymore; } } class Worker extends Employee { private int days; private int Salary; public Worker (int days,int Salary) { this .days=days; this .Salary=Salary; } public int getSalary () { return this .Salary*this .days; } }
异常代码填空 下面程序抛出了一个“异常”并捕捉它。请在横线处填入适当内容完成程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Main { static void procedure () throws IllegalAccessException { System.out.println("inside procedure" ); ___ ___ IllegalAccessException ("demo" ) ; } public static void main (String args[]) { try { procedure(); } catch (___) { System.out.println("捕获:" + e); } } }
根据异常的知识点直接填空:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Main { static void procedure () throws IllegalAccessException { System.out.println("inside procedure" ); throw new IllegalAccessException ("demo" ); } public static void main (String args[]) { try { procedure(); } catch (IllegalAccessException e) { System.out.println("捕获:" + e); } } }
处理异常输入 使用异常处理输入机制,让程序变得更健壮。
main方法
输入n,创建大小为n的int数组。
输入n个整数,放入数组。输入时,有可能输入的是非整型字符串,这时候需要输出异常信息,然后重新输入。
使用Arrays.toString
输出数组中的内容。
输入样例
输出样例
1 2 3 java.lang.NumberFormatException: For input string: "a" java.lang.NumberFormatException: For input string: "b" [1, 2, 4, 5, 3]
这里需要知道捕获的异常信息输出即可得到题目所给的输出,捕获了异常之后输出异常信息:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import java.util.Arrays;import java.util.Scanner;public class Main { public static void main (String[] args) { Scanner scanner = new Scanner (System.in); int n = scanner.nextInt(); int [] array = new int [n]; for (int i = 0 ; i < n; i++) { String next = scanner.next(); try { array[i] = Integer.parseInt(next); } catch (NumberFormatException e) { System.out.println(e); i--; } } System.out.println(Arrays.toString(array)); scanner.close(); } }