1.类和对象的区别
- 类是抽象的,概念的,代表一类事物,是自定义的数据类型。
- 对象是具体的,实际的,代表一个具体事物,是实例。
- 类是对象的模板,对象是类的一个个体,对应一个实例。
2.对象在内存中的存在形式
真正的对象是堆中的数据,栈中的cat只是对象引用,对象名称。
3.类和对象的内存分配机制
栈:一般存放基本数据类型(局部变量)
堆:存放对象(Cat cat、数组)
方法区:常量池(常量、字符串),类加载信息
4.Java常见对象流程分析
- 先加载类信息,只会加载一次
- 在堆中分配信息,进行初始化
- 把地址赋给对象引用,对象引用指向对象
- 初始化属性,字符串需要在常量池中创建
注意:
Person a = new Person();
a.age 假设存在age int类型 可以输出 无初始化为0
a = null;
a.age 不存在 出现异常 a直接无指向 不是空Person
5.方法调用机制
6.方法好处
- 提高代码复用性
- 实现细节封装,供用户调用,不用关注方法如何实现
7.方法使用细节
同一个类直接调用方法
引用数据类型传递的是地址,可以通过形参影响实参。
基本数据类型是值传递。
方法中对引用形参修改,可能影响实参内容,不影响实参指向。
8.递归
- 执行一次方法,就创建一个新的受保护的独立空间(栈空间)
- 方法局部变量式独立的,不会相互影响
- 方法中是引用类型变量,共享数据
- 必须有退出条件
- 递归必须向退出条件逼近
public class Fibonacci {
public static void main(String[] args) {
System.out.println("factorial = " + factorial(5));
System.out.println("fibonacciNum = " + fibonacciNum(7));
System.out.println("monkeyEatingPeachOne = " + monkeyEatingPeachOne(10,1));
System.out.println("monkeyEatingPeachEve = " + monkeyEatingPeachEve(8));
}
public static int factorial(int n){
if (n == 1){
return 1;
}else {
return factorial(n-1) * n;
}
}
public static int fibonacciNum(int n){
if (n == 1 || n == 2){
return 1;
}else {
return fibonacciNum(n-1) + fibonacciNum(n - 2);
}
}
public static int monkeyEatingPeachOne(int day, int n){
if (day == 1) {
return n;
}else {
return monkeyEatingPeachOne(day - 1 , (n + 1) *2);
}
}
public static int monkeyEatingPeachEve(int day){
if (day == 10) {
return 1;
}else {
return (monkeyEatingPeachEve(day+1)+1)*2;
}
}
}
public class MiGong {
public static void main(String[] args) {
int[][] arr = new int[7][7];
for (int i = 0 ; i < 7; i++ ){
arr[0][i] = 1;
arr[6][i] = 1;
}
for (int i = 1 ; i < 6; i++ ){
arr[i][0] = 1;
arr[i][6] = 1;
}
arr[3][1] = 1;
arr[2][2] = 1;
arr[2][3] = 1;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
System.out.println("========老鼠出发========");
miGong(arr,1,1);
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
public static boolean miGong(int[][] arr, int x, int y){
if (arr[5][5] == 2){
return true;
}else {
if (arr[x][y] == 0){
arr[x][y] = 2;
if (miGong(arr,x+1,y)){
return true;
}else if (miGong(arr,x,y+1)){
return true;
}else if (miGong(arr,x-1,y)){
return true;
}else if (miGong(arr,x,y-1)){
return true;
}else {
arr[x][y] = 3;
return false;
}
}else {
return false;
}
}
}
}
public class Hannuota {
public static void main(String[] args) {
hannuota(3,'1','2','3');
}
public static void hannuota(int n,char a,char b, char c){
if (n == 1){
System.out.println(a+"->"+c);
}else {
hannuota(n-1,a,c,b);
System.out.println(a+"->"+c);
hannuota(n-1,b,a,c);
}
}
}
9.方法重载
- 方法名必须相同
- 形参列表必须不同,形参类型不是名字
- 返回值类型无要求
10.可变参数
- …接受可变参数 0-多
- 接受的可变参数可以当做数组使用
- 可以直接传递数组
- 可变参数和普通参数可一起使用,但可变参数必须在最后
- 形参列表中只能出现一个可变参数
public int sum(int... nums){
}
public int sum(int i, int... nums){
}
public int sum(int... i1, int... i2){
}
11.作用域
- 主要变量就是属性(成员变量)和局部变量
- 局部变量一般是成员方法中定义的变量
- 作用域分为属性,局部变量
- 属性可以不赋值,直接使用,因为有默认值
- 局部变量必须赋值才能使用,因为没有默认值
- 属性和局部变量可以重名,访问时遵循就近原则
- 在同一作用域中,同一方法,局部变量不能重名
- 属性生命周期长,伴随对象创建而创建,伴随对象的销毁而销毁。
- 局部变量生命周期较短,伴随代码块的执行而创建,伴随代码的结束而销毁。
- 属性可以本类使用,或其他类使用,对象调用
- 局部变量只能本类对应方法使用
- 属性可以加修饰符
- 局部变量不可以加修饰符
12.构造器
构造器完成新对象的初始化。构造器初始化对象不是创建对象。
如果一个类没有构造器,就会提供一个默认的无参数构造器,这个构造器将所有的实例字段设置为默认值。
如果类中提供了至少一个构造器,但是没有提供无参数的构造器,那么构造对象时如果不提供参数就是不合法的。说明构造器可以重载。
- 构造器的修饰符可以默认
- 构造器没有返回值
- 方法名和类名一致
- 参数列表和成员方法一致
- 构造器的调用由系统完成
class Text{
int a;
int b;
int c;
Text(int a, int b){
this.a = a;
this.b = b;
}
Text(int a, int b, int c){
this(a,b);
this.c = c;
}
}
13.对象创建流程分析
- 加载类信息(.class),只会加载一次
- 在堆中分配空间
- 完成对象初始化,先是默认初始化,然后显式初始化,最后构造器初始化
- 对象堆中的地址返回给栈中引用对象
14.this
java虚拟机会给每个对象分配this,代表当前对象。
简单说,哪个对象调用,this代表哪个对象。
-
this关键字可以用来访问本类的属性,方法,构造器 -
this用于区分当前类的属性和局部变量 -
访问成员方法的语法:this.方法名 -
访问构造器语法:this(参数列表)注意只能在构造器使用,且只能在构造器中访问另一个构造器,必须在第一条语句 -
this不能在类定义的外部使用,只能在类定义的方法中使用
15.一些练习题
import java.util.Random;
import java.util.zip.Adler32;
public class Homework {
public static void main(String[] args) {
System.out.println(new A01().max(1.2,2.2,3,13));
String[] arrs = new String[]{"1","a","c"};
System.out.println(new A02().find(arrs,"a"));
Book book = new Book();
book.price = 190;
book.updatePrice();
System.out.println(book.price);
int[] ints = {1, 2, 3, 4, 5};
int[] ints1 = new A03().copyArr(ints);
int[] ints2 = new A03().copyArrNew(ints);
System.out.println(ints.hashCode());
System.out.println(ints1.hashCode());
System.out.println(ints2.hashCode());
Text text = new Text(1,2,3);
Tom tom = new Tom();
int[] cais = {0,0,0};
tom.cai(cais);
}
}
class A01{
public double max(double... nums){
double num = nums[0];
for (int i = 1; i < nums.length; i++) {
if (num < nums[i]){
num = nums[i];
}
}
return num;
}
}
class A02{
public int find(String[] arrs,String s){
for (int i = 0; i < arrs.length; i++) {
if (s.equals(arrs[i])){
return i;
}
}
return -1;
}
}
class Book{
int price;
public void updatePrice(){
if (this.price > 150){
this.price = 150;
}else if (this.price > 100){
this.price = 100;
}
}
}
class A03{
public int[] copyArr(int[] arrs){
int[] copyarrs = new int[arrs.length];
copyarrs = arrs;
return copyarrs;
}
public int[] copyArrNew(int[] arrs){
int[] copyarrs = new int[arrs.length];
for (int i = 0; i < copyarrs.length; i++) {
copyarrs[i] = arrs[i];
}
return copyarrs;
}
}
class Text{
int a;
int b;
int c;
Text(int a, int b){
this.a = a;
this.b = b;
System.out.println(""+a+b+c);
}
Text(int a, int b, int c){
this(a,b);
this.c = c;
System.out.println(""+a+b+c);
}
}
class Tom{
int hand;
public void cai(int... a){
System.out.println("Tom\t玩家\t结果");
Random random = new Random();
int win = 0;
for (int i = 0; i < a.length; i++) {
hand = random.nextInt(3);
if (a[i] == 0){
if (hand == 0) System.out.println("石头\t石头\t平局");
else if (hand == 1) {
System.out.println("剪刀\t石头\t赢了");
win++;
}
else System.out.println("布\t石头\t输了");
}else if (a[i] == 1){
if (hand == 0) System.out.println("石头\t剪刀\t输了");
else if (hand == 1) System.out.println("剪刀\t剪刀\t平局");
else {
System.out.println("布\t剪刀\t赢了");
win++;
}
}else if (a[i]== 2){
if (hand == 0) {
System.out.println("石头\t布\t赢了");
win++;
}
else if (hand == 1) System.out.println("剪刀\t布\t输了");
else System.out.println("布\t布\t平局");
}else {
System.out.println("输入错误");
}
}
System.out.println("赢了"+win+"次");
}
}
16.包
包的本质:实际就是创建不同的文件夹/目录来保存文件
命名规则:
- 只能包含数字、字母、下划线、小圆点
- 不能用数字开头,不能是关键字或保留字
命名规范:
- 一般是小写字母和小圆点
- com.公司名.项目名.业务模块名
注意事项:
- package作用是声明当前类所在的包,需要放在类的最上面,一个类中最多只有一个package
- import指令位置在package下,可以多句顺序无要求
17.访问修饰符
控制方法和属性的访问权限
- 公开 publi 对外公开
- 受保护 protected 对子类和同一个包中的类公开
- 默认 没有修饰符 向同一个包的类公开
- 私有 private 只有类本身可以访问 不对外公开
访问级别 | 访问控制修饰符 | 同类 | 同包 | 子类 | 不同包 |
---|
公开 | public | √ | √ | √ | √ | 受保护 | protected | √ | √ | √ | × | 默认 | 没有修饰符 | √ | √ | × | × | 私有 | private | √ | × | × | × |
18.封装
理解好处:
- 隐藏实现细节
- 对数据进行验证,保证安全合理
如有特殊需求,而原始构造器无法满足需求,可以在构造器中调用set方法。
19.继承
提高代码复用性
多个类存在相同的属性和方法时,可以从这些类中抽象出父类,在父类中定义这些相同的属性和方法,所有的子类不需要重新定义这些属性和方法,只需要通过extends来声明继承父类即可。
- 子类会自动拥有父类定义的属性和方法。
- 父类又叫超类,基类。
- 子类又叫派生类。
子类必须调用父类构造器,父类构造器先被调用(构造器中默认有super()😉
父类没有无参构造器,则需在子类指定super构造器
super在使用时必须在构造器第一行,所以this和super不能共存(this也只能在第一行)
Object是所有类的超类,所以创建对象引用时会从最上层(Object)一直无参构造至对象引用
IDEA中选中类名ctrl+H查看继承关系
Java中只能继承一个类,单继承机制
子类父类满足is-a关系,有关系再继承,无关系继承毛
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9HOPH0tu-1654265714673)(C:\Users\shiyuhang\AppData\Roaming\Typora\typora-user-images\image-20220530225224693.png)]
获取属性和方法,从子类层层向上逐个查找,就近原则
20.super
访问父类属性/方法,但不能访问父类的private属性/方法
访问父类构造器只能在构造器第一句只能出现一句super(参数列表);
区别点 | this | super |
---|
访问属性 | 访问本类中的属性,如果本类没有此属性则从父类中继续查找 | 从父类开始查找属性 | 调用方法 | 访问本类中的方法,如果本类没有此方法则从父类继续查找 | 从父类开始查找方法 | 调用构造器 | 调用本类构造器,必须放在构造器的首行 | 调用父类构造器,必须放在构造器的首行 | 特殊 | 表示当前对象 | 子类中访问父类对象 |
21.重写
方法重写也叫方法覆盖,需满足一下几点
- 子类的方法的参数,方法名称,要和父类方法的参数,方法名称完全一样
- 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型的子类
- 子类方法不能缩小父类方法的访问权限
名称 | 发生范围 | 方法名 | 形参列表 | 返回类型 | 修饰符 |
---|
重载 | 本类 | 必须一样 | 类型个数或者顺序至少一个不同 | 无要求 | 无要求 | 重写 | 父子类 | 必须一样 | 相同 | 子类重写的方法,返回的类型和父类一样或者是父类返回类型的子类 | 子类方法不能缩小父类方法的访问范围 |
22.多态
方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承的基础上的。
多态的具体体现
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型可以改变
- =左是编译类型,=右是运行类型
Animal animal = new Dog();
animal = new Cat();
多态的前提是:两个对象存在继承关系
多态的向上转型:
- 本质:父类的引用指向了子类的对象
- 语法:父类类型 引用名 = new 子类类型();
- 特点:
- 可以调用父类的成员(遵守访问权限)
- 不能调用子类的特有成员(先通过编译最后才java)
- 最终运行方法看子类实现
多态的向下转型:
- 语法:子类类型 引用名 = (子类类型) 父类引用
- 只能强转父类的引用,不能强转父类的对象
- 要求父类的引用必须是指向new的子类类型
- 向下转型后可以调用子类类型中的所有成员
package polymorphism;
public class Test {
public static void main(String[] args) {
Animal animal = new Cat("huamao");
System.out.println(animal);
Cat cat = (Cat) animal;
System.out.println(cat);
cat.eat();
}
}
class Animal{
String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
'}';
}
}
class Cat extends Animal{
public Cat(String name) {
super(name);
}
public void eat(){
System.out.println("chiyu");
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
class Dog extends Animal{
public Dog(String name) {
super(name);
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
'}';
}
}
属性没有重写,属性的值看编译类型,方法看运行类型。
package polymorphism;
public class Test {
public static void main(String[] args) {
Animal animal1 = new Cat("hua");
System.out.println(animal1.age);
System.out.println(animal1);
}
}
class Animal{
String name;
int age = 10;
public Animal(String name) {
this.name = name;
}
@Override
public String toString() {
return "Animal{" +
"name='" + name + '\'' +
'}';
}
}
class Cat extends Animal{
int age = 1
;
public Cat(String name) {
super(name);
}
public void eat(){
System.out.println("chiyu");
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
'}';
}
}
instanceOf比较操作符,用于判断对象的运行类型是否为XX类型或XX类型的子类型
多态的应用:
- 多态数组,数组的定义类型为父类类型,里面保存的实际元素类型为子类类型
- 多态参数,形参使用父类类型,实参可以为子类(向上转型)
22.1.动态绑定机制
- 调用对象方法时,该方法会和该对象的内存地址/运行类型绑定
- 当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用
正常调用,方法重写
package Dynamic;
public class DyTest {
public static void main(String[] args) {
A a = new B();
System.out.println(a.sum());
System.out.println(a.sum2());
}
}
class A {
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum2() {
return i + 20;
}
public int getI() {
return i;
}
}
class B extends A {
public int i = 20;
public int sum() {
return i + 20;
}
public int sum2() {
return i + 10;
}
public int getI() {
return i;
}
}
动态绑定
package Dynamic;
public class DyTest2 {
public static void main(String[] args) {
A2 a2 = new B2();
System.out.println(a2.sum());
System.out.println(a2.sum2());
}
}
class A2 {
public int i = 10;
public int sum() {
return getI() + 10;
}
public int sum2() {
return i + 20;
}
public int getI() {
return i;
}
}
class B2 extends A2 {
public int i = 20;
public int getI() {
return i;
}
}
23.Object类
23.1.equals方法
- == 既可以判断基本类型,又可以判断引用类型
- == 如果判断基本类型,判断的是值是否相等
- == 如果判断引用类型,判断的是地址是否相等,即使不是同一对象
- equals:是Object类中的方法,只能判断引用类型。
- equals:默认是判断地址相同,子类往往重写,用于判断内容先相同(Integer、String)。
23.2.hashCode方法
返回该对象的哈希码值,提高哈希表性能。
- 提高哈希结构容器的效率
- 两个引用,如果指向同一个对象,则哈希值肯定一样
- 两个引用,如果指向的不同对象,则哈希值不同
- 哈希值主要是根据地址得到,但不能完全等价于地址
23.3.toString方法
默认返回:全类名+@+哈希值十六进制
- 子类往往重写toString方法,用于返回属性值
- 重写toString方法,打印对象或拼接对象时,都会自动调用该对象的toString
- 当直接输出对象时,toString方法会默认的调用
23.4.finalize方法
- 对象被回收时,系统自动调用finalize方法,子类可以重写,做一些释放资源操作
- 当对象无引用,jvm就认为这个对象时一个垃圾对象,就会使用垃圾回收机制来销毁该对象,在销毁前会先调用finalize方法
- 垃圾回收机制调用,是由系统来决定的(即有自己的GC算法),也可以通过System.gc()主动触发垃圾回收机制,运行时不阻塞代码
24.类变量类方法
24.1.类变量
static变量和jdk版本有关,7之后静态域存储于定义类型的Class对象中,Class对象如同堆中其他对象一样,存在于GC堆中。
- static变量是同一个类所有对象的共享变量,所以修改和使用是对同一变量的使用
- static类变量,在类加载的时候就生成了,就算没有初始化,类一旦加载便可以使用
- static类变量遵循访问修饰符
- 生命周期是随类加载开始,类消亡而消亡
访问:
- 类名.类变量名(推荐)/对象.类变量名
- 非静态变量不可以类名.类变量名
24.2.类方法
当方法不涉及使用对象,可以设计为类方法,提高开发效率。
例如工具类:Math、Arrays、Collections等
- 类方法和普通方法都是随类加载而加载,把结构信息存储来方法区
- 类方法中无this、super参数,普通有this、super
- 类方法中只能使用类变量和类方法,普通都可
访问:
- 类名.类方法名(推荐)/对象.类方法名
- 非静态方法不可以类名.类方法名
25.代码块
- 抽取相同的代码,减少冗余
- 创建对象优先调用代码块
- 静态代码块随着类加载而加载只会调用一次
- 普通代码块,每创建一次对象则会调用一次
- 子类调用,父类也会加载
- 调用静态方法和属性时,不会调用普通代码块,会调用静态代码块
- 代码块调用优先于构造器
创建对象时:
- 从父类开始初始化静态方法静态属性
- 如果创建了对象,从该对象的父类开始逐步执行普通方法和构造器
- 从父类开始,将父类中所有普通代码块和普通属性的初始化和构造器调用结束
- 如果创建了对象,从该对象的父类开始逐步执行普通方法和构造器
package Dmk;
public class Text {
public static void main(String[] args) {
new C();
}
}
class A{
static public int a = new A().a1();
static public int b = new B().hah();
static public int c;
int d = a1();
static {
System.out.println("aaa");
}
{
System.out.println("aaa111");
}
static public void a(){
System.out.println("a()");
}
public int a1(){
System.out.println("a1()");
return 1;
}
public A() {
System.out.println("hhh");
}
}
class B extends A{
{
System.out.println("bbb");
A.a();
new A().a1();
}
int hah(){
System.out.println("bhah");
return 1;
}
}
class C extends B{
static public int a = 1;
static {
new A().a1();
}
}
26.单例设计模式
单例设计,所谓类的单例设计模式,就是采取一定的方法保证在整个软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。
单例模式有两种类型,饿汉式,懒汉式
饿汉式(类加载对象就存在了,饿汉着急呀)
package Dl;
public class Eh {
public static void main(String[] args) {
Girl instance = Girl.getInstance();
System.out.println(instance);
}
}
class Girl{
private String name;
private static Girl g = new Girl("ch");
private Girl(String name) {
this.name = name;
}
public static Girl getInstance(){
return g;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
}
懒汉式(使用时在创建对象)
观察以上代码,可以发现,我们如果要在使用时创建对象,则可以不在静态Girl中使用new,而是在getInstance()方法调用时赋给staticGirl对象,这样保证了一个Girl和使用时调用。
package Dl;
public class Lh {
public static void main(String[] args) {
Girl2 instance = Girl2.getInstance();
System.out.println(instance);
}
}
class Girl2 {
private String name;
public static int a = 1;
private static Girl2 g;
private Girl2(String name) {
this.name = name;
}
public static Girl2 getInstance() {
if (g == null){
g = new Girl2("lh");
}
return g;
}
@Override
public String toString() {
return "Girl{" +
"name='" + name + '\'' +
'}';
}
}
饿汉式懒汉式对比
- 创建对象时机不同,饿汉式是在类加载的时候就创建了对象,而懒汉式是在使用时才创建对象
- 饿汉式不存在线程安全问题,懒汉式存在线程安全问题
- 饿汉式存在浪费资源的可能,类加载了,但没有使用实例。饿汉式使用才会创建,不会浪费
27.final
final可以修饰类、属性、方法、局部变零。
- 不希望类被继承
- 不希望父类方法子类重写
- 不希望类的属性被修改
- 不希望局部变量被修改
注意:
- final修饰的属性又叫常量,通常使用大写字母下划线来命名
- final修饰属性必须赋值,之后不能修改
- 如果是final修饰的是静态属性,初始化只能是在定义时和静态代码块里
- final类不能继承,但可以实例化
- 类不是final类,方法被final修饰,只是不能重写,可以继承给子类
- final不能修饰构造器
- final和static搭配使用,使用类的属性时不会导致类的加载!
- 包装类和String是final修饰的
28.抽象类(abstract)
当父类方法不确定时,用abstract关键字修饰,这个方法是抽象方法,用abstract来修饰类,类就是抽象类
- 抽象类不能实例化
- 抽象类不一定要包含抽象方法,其他都可以有,本质还是类
- 一旦有抽象方法,类必须为抽象类
- abstract只能修饰类和方法,不能修饰属性和其他
- 因为abstract必须重写,所以和final、private、static不能一起使用
- 继承抽象类必须重写,除非也是抽象类
可以抽出一个公共方法,然后定义不确定的抽象方法,让子类继承然后实现抽象方法,使用父类公共方法。(模板设计模式)
29.接口
接口给出未实现的方法,封装在一起,类要使用方法时,继承该接口。
接口中的方法,可以是抽象方法(可以省略abstract),默认实现方法,静态方法(jdk7之后)。
接口可以统一管理方法名,使代码规范化。
- 接口不能实例化。
- 接口中的方法是public方法,可以不用abstract修饰
- 抽象类实现接口,可以不实现方法
- 普通类实现接口,必须实现所有方法
- 一个类可以实现多个接口
- 接口中的属性是public static final修饰的
- 接口不能继承其他类,可以继承多个接口
- 接口修饰符只能是public和默认
接口的多态:
- 多态参数
- 多态数组
- 多态传递
package JieKou;
public class J01 {
public static void main(String[] args) {
C c = new C();
}
}
interface A{
int a = new B().pr();
}
class B implements A{
static {
System.out.println("?");
}
{
System.out.println("???");
}
public int pr() {
System.out.println("B");
return 1;
}
}
class C extends B{
}
package JieKou;
public class J01 {
public static void main(String[] args) {
new C().pr();
}
}
interface A{
int a = 1;
}
class B implements A{
int a = 2;
}
class C extends B{
public void pr(){
System.out.println(A.a);
System.out.println(super.a);
}
}
接口继承比较
- 接口是设计方法,设计规范,让其他类实现,更加灵活,满足like-a关系,在一定程度上实现了代码的解耦
- 继承是解决代码的复用性和可维护性,满足is-a关系
30.内部类
30.1.局部内部类
- 定义在外部类的局部位置,方法或者代码块
- 可以直接访问外部类的所有成员
- 不能添加访问修饰符,但是可以使用final修饰
- 作用域在定义它的方法和代码块中
- 外部其他类不能访问
- 外部类和局部内部类重名,就近原则,如果需要访问外部类,使用外部类名.this.成员访问
30.2.匿名内部类
- 本质是类,是内部类,类系统定义名字,是一个对象,本质是继承
- 可以直接访问外部类的所有成员
- 不能添加访问修饰符
- 外部类和局部内部类重名,就近原则,如果需要访问外部类,使用外部类名.this.成员访问
- 当做实参直接传参
package NBL;
public class Niming {
public static void main(String[] args) {
As as = new As();
as.a();
as.b();
}
}
class As{
public void a(){
class P{
public void p(){
System.out.println("hhh");
}
}
new P().p();
}
public void b(){
As a = new As() {
@Override
public void c() {
System.out.println("匿名内部类");
}
};
a.c();
}
public void c(){
System.out.println("c");
}
}
30.3.成员内部类
- 定义在外部类的成员位置,没有static的修饰
- 访问外部类所有成员
- 添加任意访问修饰符
- 外部其他类调用new外部类.new成员内部类
- 外部类和局部内部类重名,就近原则,如果需要访问外部类,使用外部类名.this.成员访问
30.4.静态内部类
- 定义在外部类的成员位置,有static的修饰
- 访问外部类所有静态成员
- 添加任意访问修饰符
- 外部其他类调用new外部类.成员内部类
- 外部类和局部内部类重名,就近原则,如果需要访问外部类,使用外部类名.成员访问
package NBL;
public class Niming {
public static void main(String[] args) {
As.J j = new As().getJ();
As.J j1 = new As.J();
As.JD jd = new As().new JD();
}
}
class As{
static class J{
}
class JD{
}
public J getJ(){
return new J();
}
}
|