内部类
类中定义类就是内部类。如果一个事物的成员也是一个事物,那么就可以使用内部类的定义。
常见的内部类有:成员内部类,局部内部类,私有内部类,静态内部类,匿名内部类(最重要的。)
-
成员内部类
内部类定义在外部类的成员位置。作为成员可以使用成员修饰符(public、private、default、protected、static、(不包括final)),作为类可以继承类,可以实现接口。
特点:
内部类可以直接使用外部类的所有属性和方法,包括私有的。内部类中不可以直接定义静态的内容,除了静态常量(static final int A=5),静态的内容要定义在静态内部类中。 -
私有内部类
特点:私有内部类可以使用外部类的所有内容,包括私有的。私有内部类只能在外部类中可以通过对象使用私有内部类中的私有内容,其他类中不能使用。 -
静态内部类
(1)静态内部类可以定义静态的内容可以定义成员的内容。
(2)在静态内部类中使用外部类中的非静态的内容,要通过外部类的对象去使用。
(3)在外部类中可以通过类名使用静态内部类中的静态内容,需要通过对象使用静态内部类中的成员内容。
(4)在其他类中可以通过外部类名.静态内部类名.静态内容使用静态内部类中的静态内容。
new 外部类.静态内容类()
创建静态内部类的对象使用静态内部类中的成员。 -
局部内部类
方法中定义内部类
1.局部内部类不可以使用成员修饰符修饰(比如:public,static…不包括final)
2.只能在当前定义局部内部类的方法中可以通过内部类的对象使用内部类中的成员,通过类可以使用静态内容。
3.局部内部类所在的方法的参数,在jdk1.8之后默认,1.7之前需要显示定义 -
匿名内部类
没有名字的内部类,简化了没有独自作用(功能实现)的子类。
(1)用完就销毁,不能使用第二遍。
new Smoking(){ //--匿名内部类的类体 是new后面的接口或者父类的实现类|子类的类体
@Override
public void smoke() {
System.out.println("我抽的不是烟,抽的是寂寞..");
}
@Override
public void cat() {
System.out.println("吸猫...");
}
}.cat();
interface Smoking{
void smoke();
void cat();
}
(2)引用接收匿名内部类对象的地址—接口多态
Smoking s=new Smoking(){ //--匿名内部类的蕾体 是new后面的接口或者父类的实现类|子类的类体
public void smoke() {
System.out.println("我抽的不是烟,抽的是寂寞..");
}
@Override
public void cat() {
System.out.println("吸猫...");
}
};
s.smoke();
s.cat();
(3)方法的参数
useUSB(new USB(){
@Override
public void start() {
System.out.println("开始使用移动硬盘");
}
@Override
public void end() {
System.out.println("结束使用移动硬盘");
}
});
useUSB(new USB(){
@Override
public void start() {
System.out.println("开始使用键盘");
}
@Override
public void end() {
System.out.println("结束使用键盘");
}
});
}
static void useUSB(USB usb){
usb.start();
usb.end();
}
}
(4)Lambda表达式
是为了简化匿名内部类.
语法:
()重写的抽象方法的参数列表
->箭头符号,箭头函数,Lambda符号
{}重写的抽象方法的方法体
前提:必须是函数式接口
函数式接口:只有一个抽象方法的接口就是函数式接口
@FunctionalInterface : 强制检查是否为函数式接口
public class LambdaDemo {
public static void main(String[] args) {
/*Code c=new Code(){
@Override
public void code(int haha) {
System.out.println("边敲代码边哄女朋友");
}
};*/
//Lambda表达式写法1
/*Code c=()->{
System.out.println("边敲代码边哄女朋友");
};*/
//写法2:如果方法的语句体只有1句,前后的{}可以省略
// Code c=()->System.out.println("边敲代码边哄女朋友");
//写法3: 如果存在参数,参数的数据类型可以省略
// Code c=(i,m)->System.out.println("边敲代码边哄女朋友"+i+"次");
//写法4:如果存在参数,并且参数只有一个前后的()可以省略
/*Code c= i ->{
System.out.println("边敲代码边哄女朋友"+i+"次");
return -1;
};
System.out.println(c.code(100));*/
//写法5: 有返回值类型的方法,如果方法体语句只有1句,并且是return语句的时候,这时前后{},包括return都可以省略
Code c= str -> str.length();
System.out.println(c.code("因为"));
}
}
//函数式接口
@FunctionalInterface
interface Code{
// void code();
int code(String a);
}
数组
数组[],相同数据类型的有序集合
数组的特点
- 数组是引用数据类型
- 数组是定长的,长度一旦确定不可改变
- 数组中所有数据的数据类型保持一致
- 数组中的数据存在顺序(索引:从0开始)
数组的声明方式
- 数据类型[] 数组名;
数据类型:可以是基本数据类型|引用数据类型
数据类型的作用:规定数组中所有数据的数据类型 - 数据类型 数组名[]; --不推荐使用
数组的初始化
- 动态初始化:先创建后赋值
数据类型[] 数组名 = new 数据类型[长度];
数组中的数据如果不赋值有默认值 String–null,int–0,double–0.0 ,char–’ ',boolean–false - 静态初始化:创建的同时赋值
数据类型[] 数组名 =new 数据类型[]{值1,值2,值3…};
数据类型[] 数组名 ={值1,值2,值3…}; --推荐
数组的长度获取
- 数组名.length
数组中最后一个数据的下标
- 数组名.length-1
数组的遍历
1)普通for循环,可以获取可以修改,因为是操作索引(位置)。
2)增强for循环|for…each ,只能获取每一个数据,不能修改。
for(数据类型 变量名: 数组名|容器名){
变量–>指代数组中的每一个数据
}
使用数组时常见的异常
-
NullPointerException 空指针异常
对象指向为null,根据这个对象做一些操作,可能对出现空指针 -
ArrayIndexOutOfBoundsException 数组索引越界异常
索引为负数
索引超出最大范围
可变参数
可变参数:数据类型相同的0~多个参数
- 1.使用…表示可变参数
- 2.编译器会自动为可变参数隐式创建一个数组,通过操作数组的方式使用可变参数
- 3.可变参数必须放在参数列表的最后位置
public class ParaDemo {
public static void main(String[] args) {
test(1,"","",1,false);
}
//至少接收一个参数,可以接收多个参数
public static void test(int name,Object ...arr){
System.out.println(name);
for(Object n:arr){
System.out.println(n);
}
}