访问修饰符 (访问控制)
作用:控制当前代码的可见范围 目的:保护程序的合法性,安全性,健壮性
属性的封装:属性私有化,方法公开化
public(公开的):任意位置都可以访问,权限最大
protected(保护的):一般存在父级代码中,当前类/同包类/子类 可见
默认的:默认访问修饰符是不建议的 当前类/同包类 可见
private(私有的):权限最小 当前类 可见
final
final代表的是最终的意思,可以修饰类、属性、方法
- 修饰属性:final修饰符变量要么在声明时初始化,要么在构造方法中初始化
- 修饰方法:final修饰的方法不可以被重写,所以存在于父级代码中
- 修饰类:final修饰的类不可以被继承
//final测试演示类
public class FinalDemo {
private final int a; //final修饰符变量要么在声明时初始化
FinalDemo() {
a = 10; //final修饰符变量要么在构造方法中初始化
}
void show() {
// a = 10; //final修饰符变量不能再普通方法中初始化
}
}
final class Aoo { //final修饰的类不可以被继承
public final void test() { //final修饰的方法不可以被重写
}
}
class Boo/* extends Aoo*/ {
// public void test() { //不可以重写
//
// }
}
static (静态变量)
静态资源:
如:
每个学生的杯子属于对象吗?属于,属于个人的
饮水机属于对象吗?不属于,但可以被对象共享。----->静态资源
- 实例变量:属于对象的!特点:有多少个对象就有多少份,在堆中
- 实例变量的访问:通过对象名打点的形式访问
- 静态变量:属于类的!特点:有且只有一份,被所有对象共享,在方法区中存储
- 静态变量的访问:通过类名打点的形式访问
- 静态变量适用性:当一份资源需要被多个对象共享时可以做成静态资源
方法区特点:一个类应该有一份.class字节码文件,当类被首次使用时,该类的.class 字节码文件会被加载到方法区中,加载且只加载一次
JVM分配空间:栈区,堆区,方法区
栈区:放局部变量的区域
堆区:放对象的区域
方法区:用来加载.class字节码文件(类中的静态变量,类中的方法(构造方法/静态方法/普通方法))
class Coo {
public int a;//实例变量:属于对象的,有多个对象有多少份
public static int b;//静态变量:属于类的,只有一份被所有对象共享
Coo() {
a++;
b++;
}
void show() {//普通方法
this.a = 0;//访问类实例成员默认有个this的写法
Coo.b = 0;//访问类静态成员默认有个类名点的写法
System.out.println("实例变量a的值:" + a + ",静态变量b的值:" + b);
}
static void show2() {//静态方法中:无法使用this
// this.a = 1; 普通实例成员不可直接在static修饰的方法中调用
// this.show();普通方法不可直接在static修饰的方法中调用
Coo.b = 1;//静态方法可直接访问静态的内容.
}
}
static (静态方法)
用static修饰的方法称之为静态方法
- 静态方法属于类,通过类名打点调用
- 静态方法存储在方法区中
- 静态方法时没有隐式this传递的,所以静态方法是无法访问类中实例成员(普通实例变量,普通方法)
- 静态方法的适用性:静态方法一般存在于工具类中,对于外部来讲调用方便,只需要类名点的形式就可以调用该方法
class Coo {
private int a; //实例变量:属于对象的,有多少个对象有多少份
public static int b; //静态变量:属于类的,有且只有一份被所有对象共享
Coo() {
a ++;
b ++;
}
void show() { //普通方法
this.a = 0; //访问类实例成员默认有个this
Coo.b = 0; //访问静态成员默认有个类名点的写法
System.out.println("实例变量a的值:" + a + "静态变量b的值:" + b);
}
static void show2() { // 静态方法中:无法使用this
// a = 0; 普通实例成员不可以在static修饰的方法中调用
// this.show(); 普通方法不可以在static修饰的方法中调用
Coo.b = 2; //静态方法可以直接访问类的静态内容
}
}
static (静态代码块)
- 用static修饰的代码块称之为静态代码块
- 静态代码块属于类,当类被首次加载时,会自动调用静态代码块且只调用一次
- 静态代码块适用性:当成员都是静态成员时,也无需外部创建对象,类中静态成员初始化赋值的功能,可以交给静态代码块来完成
/*测试静态代码块的类*/
public class StaticDemo2 {
public static void main(String[] args) {
// Doo doo1 = new Doo();
// Doo doo2 = new Doo();
Doo doo3 = new Doo();
// Doo.a = 2; //访问类中的静态成员 也叫使用类,如果是首次使用则会加载
}
}
class Doo {
public static int a = 2;
Doo() { //创建多少个对象 则执行多少次 构造方法的作用:创建对象时可以为对象初始化数据
System.out.println("Doo类的构造方法执行了");
}
static { //静态代码块:类被首次加载时执行,且只加载一次 静态代码块的作用:一般用于为静态成员初始化使用的语法
System.out.println("Doo类被加载了。。我执行了。。");
}
}
常量
用static final修饰的属性则是常量,常量结合static和final的特性
特性:常量可以通过类名打点形式访问,不能二次修改且声明时需要初始化
常量命名:要求纯大写,多个单词之间用下划线隔开
常量的适用性:当有一份数据,确定后几乎不会发生改变的,也不会频繁修改得,那么可以作为常量来表示,常量一般也可以用于表示一些固定状态的使用
/*常量的使用演示类*/
public class StaticFinalDemo {
public static void main(String[] args) {
// System.out.println(Eoo.a);
// Eoo e = new Eoo();
// System.out.println(e.b);
/*1.先将Eoo类字节码文件加载到方法区
* 2.输出静态变量a的值*/
System.out.println(Eoo.a);
/*在编译期间使用常量,本质上就是将常量的值进行访问(不会执行static代码块)*/
System.out.println(Eoo.C);
}
}
class Eoo {
public static int a; //静态变量
public final int b = 1; //final修饰的变量
public static final int C = 100;//常量
static {
System.out.println("静态代码块执行了、、、、");
}
}
抽象方法(半成品)
- 用abstract修饰的方法称之为抽象方法
- 抽象方法需要存在于抽象类
- 抽象方法不能有方法体
- 抽象方法必须要子类重写
抽象类
- 用abstract修饰的类称之为抽象类
- 抽象类不能被实例化对象
- 抽象类只是能在普通类的基础上可以放抽象内容而已
- 抽象类一定要有子类实现的,否则抽象类没有意义
抽象方法的意义:
1)遵循面向对象设计原则,如果父类中提供的方法子类都不能用是不是需要重写?
如果做成普通方法,子类是不是可以重写 也可以不重写?
目的:为了约束子类必须重写,不重写代码报错
2)子类都重写了,父类的抽象方法还有存在的意义吗?
目的:父类中存在的抽象方法的意义是为了向上造型,调用父类执行子类
内部类 (应用率不高)
内部类:类中套个类,类结构中的类称之为内部类
- 内部类不具备可见性
- 内部类共享外部类成员,可以直接访问。但如果外部类成员命名与内部类成员命名冲突时,那么我们可以明确写外部类名.this.xx即可
class Aoo { //外部类
class Boo { //内部类
}
}
匿名内部类 (应用率高)
匿名内部类:没有名字的内部类称之为匿名内部类
适用性:当一个子类仅仅只是为了实现重写父类中的某个功能时,而其他地方根本不用该子类,那么我们可以使用匿名内部类的方式,目的:让面相实现开发,而不关心语法,更关心的是逻辑如何实现
- 匿名内部类的使用:只会存在于只是重写父类方法的情况才会使用
- 匿名内部类访问外部类成员:对于
//1.创建一个匿名内部类,花括号就是匿名子类的类体
//2.运行时创建的子类对象赋值给sub
//3.通过sub调用重写的show方法
SupperDemo sub = new SupperDemo() {
@Override
void show() {
// sub.a = 20; // 匿名内部类访问外部类成员 会自动修饰为final, a不可二次修改
System.out.println(a); //可以访问
System.out.println("匿名内部类重写了父类中的show方法");
}
};
sub.show();
问:内部类有没有独立的.class字节码文件?
答:无论是成员内部类还是匿名内部类都有.class字节码文件
数组扩容
Arrays.copy
int[] array = {}; //为array数组创建了一个数组对象, 数组长度为0
int a = 100;
//copyOf: 1.要扩容的数组对象 2.基于原数组长度的基础上 + 或 - 要扩容或缩容的容量
array = Arrays.copyOf(array, array.length + 1);
System.out.println("扩容后" + array.length);
array[array.length - 1] = a;
System.out.println("存数后" + Arrays.toString(array));
System.arrayCopy
int[] a = {50, 60, 70, 80};
int[] b = {0, 0, 0, 0};
/*arrayCopy的5个参数
* 1.要拷贝的原数组
* 2.从原数组哪个下标开始拷贝
* 3.要拷贝到的目标数组
* 4.从目标数组哪个下标开始装载
* 5.拷贝的数量, 目标数组长度 - 目标数组装载的下标
(注意:拷贝的数量不能超过目标数组容纳的范围)*/
System.arraycopy(a, 1, b, 1, a.length - 1);
接口
定义:接口是一组行为的规范,接口并不关心多个类之间是否是一种的关系,只关心这些类的行为是否一样,一个类可以实现多个接口,一般一个接口只代表一个行为,不要做大而全的接口,要做小而精的接口
- 接口是一种数据类型,是引用类型,同样也有.class字节码文件
- 接口使用interface关键字来定义
- 接口中只能放常量和和抽象方法
- 实现类必须重写接口中的所有方法 使用implement戳上接口名来实现
- 实现类又要继承类 又要实现接口的方法 那么先继承后实现接口方法
- 实现类可以实现多个接口,实现时接口名之间用逗号隔开
- 接口之间是可以继承的
抽象类和接口的区别
-
语法区别:
- 抽象类可以有构造方法 | 接口没有
- 抽象类可以有普通变量、方法/抽象方法 | 接口只能放常量,抽象方法1.8支持静态方法
- 抽象类成员可选择不同访问修饰符 | 接口默认都是public
- 一个类只能继承类 | 接口可以继承多个接口
-
设计使用区别
- 继承:多个类之间存在共性的属性和行为时,且这些类在概念上是一种的关系,可以用继承来复用优化代码
- 继承好处:复用代码(属性),可以向上造型,调父执行子
- 继承缺点:耦合度高,牵一发而动全身
- 接口:多个类之间存在共有行为时,不管这些类概念上是否是一种的关系,可以用接口来代表这些类的行为
- 接口好处:代表行为,可以向上造型,调用父执行,接口是可以多实现
- 高内聚:一个类或一个方法尽可能只干相关的事情 低耦合:类与类之间的关系尽量松散
- 继承:多个类之间存在共性的属性和行为时,且这些类在概念上是一种的关系,可以用继承来复用优化代码
多态
在程序中多态指的是,一个父类下的行为子类有不同的实现
向上造型:引用类型中的自动类型转换
能够向上造型的语法:实现继承关系 声明父 new子 | 实现关系 声明接口 new 实现类
向下转型:引用类型中的强制类型转换
引用类型中能否强制转换成功,具体参考以下两个条件
- 条件1:要强转引用类型变量中的对象,就是要转换的这个类型
- 条件2:要强转引用类型变量中的对象,实现了要转换的这个接口
强转时建议用instanceof判断是否强转成功