内部类
内部类可以访问外部类的变量(包括private),外部类要访问内部类方法,要创建内部类对象。
成员内部类(类中方法体外)
一个类想要调用成员内部类:Outer.Inner inner = new Outer().new Inner();
以上方法对与public内部类可行,但内部类一般用于隐藏在类里面,所以一般是private,一般写一个方法来被调用。
class Outer {
public class Inner {
public void show(){
System.out.println("内部类");
}
}
//对外提供调用的方法
public void show() {
Inner in = new Inner();
in.show();
}
}
局部内部类(方法体内)
也是间接调用方法,方法体中调用内部类。
class Outer {
public void show() {
class Inner {
public void show(){
System.out.println("内部类");
}
}
Inner in = new Inner();
in.show();
}
}
匿名内部类(局部内部类的一种)
前提:存在一个类或接口,这里的类可以是具体类也可以是抽象类。
本质:是继承了该类或实现了该接口的子类对象。
interface inter {
void show();
}
class Outer {
public void show() {
new inter(){
@Override
public void show() {
System.out.println("匿名内部类");
}
}.show();
Inter inter = new inter(){
@Override
public void show() {
System.out.println("匿名内部类");
}
};
inter.show();
}
}
异常
Error:严重问题,不需要处理,代码无法处理。
Exception:异常类,他表示程序本身可以处理的问题。
RuntimeException:在编译时不检查,出现问题后,我们需要回过头修改代码。
非RuntimeException:在编译时检查。
- Throwable(所有异常的祖宗)
它有三个成员方法
public static void main(String[] args){
try {
throw new ArrayIndexOutOfBoundsException("message");
} catch (ArrayIndexOutOfBoundsException e) {
//message
System.out.println(e.getMessage());
//java.lang.ArrayIndexOutOfBoundsException: message
System.out.println(e.toString());
/* java.lang.ArrayIndexOutOfBoundsException: message
at Main.main(Main.java:4) */
e.printStackTrace();
}
}
Throwable有多个构造方法,有参构造messgae传入给成员变量detailMessage赋值,存储异常信息。
大多使用e.printStackTrace();
打印完整。
- try-catch
int[] array = {1, 2, 3};
try {
System.out.println(array[3]);//new ArrayIndexOutOfBoundsException
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("数组越界");
e.printStackTrace();
}
- throws
只是抛出异常,并没有对异常进行处理,还是需要try-catch处理。
public static void main(String[] args) throws ArrayIndexOutOfBoundsException{
int[] array = {1, 2, 3};
System.out.println(array[3]);//new ArrayIndexOutOfBoundsException
System.out.println("数组越界");//异常没被处理,不会输出
}
- 自定义异常
public class Main {
public static void main(String[] args){
Checker c = new Checker();
/*
OutOfRangeException: 分数>100
at Checker.check(Main.java:13)
at Main.main(Main.java:5)
*/
try {
c.check(200);
} catch (OutOfRangeException e) {
e.printStackTrace();
}
}
}
class Checker {
public void check(int x) throws OutOfRangeException{
if (x > 100) throw new OutOfRangeException("分数>100");
else System.out.println("分数<=100");
}
}
class OutOfRangeException extends Exception {
public OutOfRangeException() {
}
public OutOfRangeException(String message) {
super(message);
}
}
泛型
它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。一提到参数, 最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?
顾名思义,就是将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型。这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。
泛型定义格式:
- <类型>: 指定一种类型的格式。这里的类型可以看成是形参
- <类型1,类型2…>: 指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
将来具体调用时候给定的类型可以看成是实参, 并且实参的类型只能是引用数据类型。
泛型类
格式:public class Generic<T>() {}
,这里的T可以是任意标识,常见的如我们E、K、V等形式的参数常用于表示泛型。
public class Main {
public static void main(String[] args){
Generic<Integer> g1 = new Generic<Integer>(1);
Generic<String> g2 = new Generic<String>("java");
System.out.println(g1.t);//1
System.out.println(g2.t);//String
}
}
public class Generic <T>{
T t;
public Generic(T t) {
this.t = t;
}
public Generic() {
}
public T getT() {
return t;
}
public void setT(T t) {
this.t = t;
}
}
泛型方法
public class Main {
public static void main(String[] args){
Generic<Integer> g1 = new Generic<Integer>();
Generic<String> g2 = new Generic<String>();
g1.show(1);
g2.show("java");
}
}
public class Generic <T>{
public void show(T x) {
System.out.println(x);
}
}
用泛型类,这样定义对象每次都要给定类型,有没有更好的方法?泛型方法就可以解决。
格式:public <T> void show(T t) {}
public class Main {
public static void main(String[] args){
Generic g1 = new Generic();
g1.show(1);
g1.show("java");
}
}
public class Generic{
public <T> void show(T x) {
System.out.println(x);
}
}
泛型接口
格式:public interface Generic <T> {}
public class Main {
public static void main(String[] args){
Generic<Integer> g1 = new GenericImpl<Integer>();
g1.show(1);
Generic<String> g2 = new GenericImpl<String>();
g2.show("java");
}
}
public interface Generic <T>{
void show(T x);
}
public class GenericImpl <T> implements Generic<T>{
@Override
public void show(T x) {
System.out.println(x);
}
}
类型通配符
为了表示各种泛型List的父类,可以使用类型通配符
- 类型通配符: <?>
- List<?>: 表示元素类型末知的List,它的元素可以匹配任何的类型
- 这种带通配符的List仅表示它是各种泛型List的父类,不能把元素添加到其中
如果说我们不希望List<?>是任何泛型List的父类,只希望它代表某一类泛型List的父类 ,可以使用类型通配符的上限
- 类型通配符上限: <? extends 类型>
- List<? extends Number>:它表示的类型是Number或者其子类型
除了可以指定类型通配符的上限,我们也可以指定类型通配符的下限
- 类型通配符 下限: <? super 类型>
- List<? super Number>:它表示的类型是Number或者其父类型
public class Main {
public static void main(String[] args) {
List<?> list1 = new ArrayList<Object>();
List<?> list2 = new ArrayList<Number>();
List<?> list3 = new ArrayList<Integer>();
System.out.println("-----------");
// 类型通配符上限
// List<? extends Number> list4 = new ArrayList<Object>();
List<? extends Number> list5 = new ArrayList<Number>();
List<? extends Number> list6 = new ArrayList<Integer>();
// 通配符下限
List<? super Number> list7 = new ArrayList<Object>();
// List<? super Number> list8 = new ArrayList<Integer>();
List<? super Number> list9 = new ArrayList<Number>();
}
}
要求该泛型的类型,只能是实参类型,或实参类型的子类类型。
public class Main {
public static void main(String[] args) {
Generic01<Number> num = new Generic01();
num.setNum(100);
showBox(num);
Generic01<Integer> num2 = new Generic01();
num2.setNum(200);
showBox(num2);
}
// 通配符上限Number
public static void showBox(Generic01<? extends Number> g1) {
Number num01 = g1.getNum();
System.out.println(num01);
}
}
public class Generic01<T> {
private T num;
public T getNum() {
return num;
}
public void setNum(T num) {
this.num = num;
}
}