一、泛型
- 概述:指的是"参数化类型",指我们在开始定义一个方法的参数时,不能对其类型有一个具体的定义,即我们后期用到它时,可能将它定义为 String\int\double…等等
这时候我们就要用到泛型来定义,首先定义参数名,等到后期需要调用的时候,在调用的地方重新定义它的数据类型 - 泛型的使用:
- 泛型类:顾名思义,就是在定义类的同时,定义一个泛型参数,指明这个类里面的有一种类型是我们泛指的某一种类型
例子:
public class GeniricClassDemo {
public static void main(String[] args) {
Person<String> p = new Person<>();
p.setData("今天也一定要努力");
p.say();
}
}
/**
* 泛型类
*/
class Person<A>{
private String name;
private int age;
private A data;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public A getData() {
return data;
}
public void setData(A data) {
this.data = data;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", data=" + data +
'}';
}
public void say(){
System.out.println(data);
}
}
- 泛型接口:与泛型类基本一致,不过分为两种情况,一种是在继承泛型接口时指定数据类型;另一种是在继承泛型接口时不指定数据类型,但在调用继承类创建对象时指定数据类型
例子:
/**
* 泛型接口
*/
public interface GenericInterface<T> {
T setData(T t);
}
/**
* 实现类
*/
public class GenericInterfaceDemo {
public static void main(String[] args) {
//1、调用指定数据类型的泛型接口类;
GeneticInterface01 text01 = new GeneticInterface01();
text01.setData("今天是个好日子");
//2、调用泛型继承类
GenericInterface02<String> text02 = new GenericInterface02<>();
text02.setData("我今天也很努力呀");
}
}
//指定数据类型
class GeneticInterface01 implements GenericInterface<String> {
private String text;
@Override
public String setData(String text) {
System.out.println(text);
return text;
}
}
//不指定数据类型
class GenericInterface02<T> implements GenericInterface<T> {
private T data;
@Override
public T setData(T data) {
System.out.println(data);
return data;
}
}
- 泛型方法:在定义方法时定义泛型,这个泛型的范围只在这个方法内有效
例子:
public class GenericMethodDemo {
public static void main(String[] args) {
haha("明天会下雨");
}
public static <A> void haha(A a){
System.out.println(a);
}
}
- 泛型限制类型:
在使用泛型时,可以指定泛型的限定区域,
例如,泛型只能是某某类的子类,某某接口的实现类,则可以这样写:
<T extends 类或接口1 & 接口2>
- 泛型的通配符 —— ?
类通配符是使用 ? 代替方法具体的类型实参
<? extends Parent> //指定了泛型类型的上届
<? super Child> //指定了泛型类型的下届
<?> //指定了没有限制的泛型类型
例子:
public class GenericMethodDemo {
public static void main(String[] args) {
//创建的对象必须是Fruit的子类
Plate<? extends Fruit> p = new Plate<Apple>();
//创建的对象必须是Apple的父类
Plate<? super Apple> m = new Plate<Fruit>();
}
}
interface Fruit {}
class Apple implements Fruit {}
class Plate<T> {
T data;
}
- 作用:
- 提高代码的复用率
- 泛型中的类型在使用时指定,不需要强制类型转换(类型安全,编译器会检查类型)
二、Java Objects类
变量和类型 | 方法 | 描述 |
---|---|---|
static int | checkFromIndexSize(int fromIndex, int size, int length) | 检查是否在子范围从 fromIndex (包括)到 fromIndex + size (不包括)是范围界限内 0 (包括)到 length (不包括)。 |
static int | checkFromToIndex(int fromIndex, int toIndex, int length) | 检查是否在子范围从 fromIndex (包括)到 toIndex (不包括)是范围界限内 0 (包括)到 length (不包括)。 |
static int | checkIndex(int index, int length) | 检查 index是否在 0 (含)到 length (不包括)范围内。 |
static < T > int | compare(T a, T b, Comparator<? super T> c) | 如果参数相同则返回0,否则返回 c.compare(a, b) 。 |
static boolean | deepEquals(Object a, Object b) | 返回 true如果参数是深层相等,彼此 false其他。 |
static boolean | equals(Object a, Object b) | 返回 true如果参数相等,彼此 false其他。 |
static int | hash(Object… values) | 为一系列输入值生成哈希码。 |
static int | hashCode(Object o) | 返回非的哈希码 null参数,0为 null的论点。 |
static boolean | isNull(Object obj) | 返回 true如果提供的参考是 null ,否则返回 false 。 |
static boolean | nonNull(Object obj) | 返回 true如果提供的参考是非 null否则返回 false 。 |
static < T > T | requireNonNull(T obj) | 检查指定的对象引用是否不是 null 。 |
static < T > T | requireNonNull(T obj, String message) | 检查指定的对象引用是否为null ,如果是,则抛出自定义的NullPointerException 。 |
static < T > T | requireNonNull(T obj, Supplier< String > messageSupplier) | 检查指定的对象引用是否为null ,如果是,则抛出自定义的NullPointerException 。 |
static < T > T | requireNonNullElse(T obj, T defaultObj) | 如果它是非 null ,则返回第一个参数,否则返回非 null第二个参数。 |
static < T > T | requireNonNullElseGet(T obj, Supplier<? extends T> supplier) | 如果它是非 null ,则返回第一个参数,否则返回非 null值 supplier.get() 。 |
static String | toString(Object o) | 返回调用的结果 toString对于非 null参数, "null"为 null的说法。 |
static String | toString(Object o, String nullDefault) | 如果第一个参数不是 null ,则返回在第一个参数上调用 toString的结果,否则返回第二个参数。 |
官方的描述文档是这样写的,那应该怎样去使用这些方法呢?举个例子:
public static void main(String[] args) {
String p = null;
System.out.println(Objects.requireNonNull(p));
}
上面这段小程序我们调用的是 requireNonNull(T obj, String message) 这个方法,如果我们的 p 为空的话,就会返回指定的异常;如果不为空的话,就会返回 p 的值。其他的方法也可以这样调用,当然,有什么需求,我们就怎么调用。
例如,我们还可以这样玩:
public class ObjectsDemo01 {
public static void main(String[] args) {
Person p = new Person();
p.setName(null);
String result = Objects.requireNonNull(p.getName());
System.out.println(result);
}
}
class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
三、Java Math类
- 方法很多,就不像上面那样一一列举了。官方的JDK文档也有相应的介绍。下面就演示一个Java Math类的方法该如何使用。
我们使用 Math.multiplyExact(int x, int y) 方法,计算两个int 变量的乘积:
public class MathDemo01 {
public static void main(String[] args) {
int x = 10;
int y = 2;
int m = Math.multiplyExact(x,y);
System.out.println(m);
}
}
毫无疑问,上面输出的结果是20(这种难度的题,我一般口算都算不出来,基本都是借助计算器~)。好啦,这个方法就暂时这样吧,看看下一个难题…
四、Java Arrays类
- Java Arrays类在开发中也非常的方便,可以快速的对数组进行查找,排序,以及对数组动态扩容。下面就通过代码来演示是如何使用的~
public class ArraysDemo01 {
public static void main(String[] args) {
int[] arr1 = {9,1,2,3,4,5,6,7,8};
System.out.println(Arrays.toString(arr1)); //打印数组内容
Arrays.sort(arr1); //排序
System.out.println(Arrays.toString(arr1));
System.out.println(Arrays.binarySearch(arr1,6)); // 查找数组中的数据
//数组的动态扩容
System.out.println(arr1.length); //原数组长度
arr1 = Arrays.copyOf(arr1,15);
System.out.println(arr1.length); //扩容后的数组长度
}
}
- 需要打印数组的内容,我们以前的操作是写一个for循环,遍历打印数组的每个下标对应的值,现在引入了Arrays类,我们只需要调用Arrays.toString()方法,就可以打印数组的内容~
- 以前对数组进行排序,常用的方法就是冒泡排序法,现在引入了Arrays类,只需要调用Arrays.sort()方法,就可以快速完成对数组的排序~
- 在查找数组中的数据时,我们以前常用的方法时二分查找法,引入Arrays类后,直接调用它的Arrays.binarySearch()方法,就可以简便的查找想要的数据~
- 除此之外,Arrays类还提供了对数组进行动态扩容的方法。底层原理是先创建一个指定长度的数组,再将原来的数组进行遍历复制到新的数组中,进而完成数组的动态扩容~~
- Arrays类还有很多便捷的方法,在开发中可以适当地运用,提高开发效率~