面向对象的编程
一、面向对象和面向过程
1.面向过程
面向过程注重怎么做
2.面向对象
面向对象注重由谁来做
3.二者联系
相互联系,相辅相成。面向对象需要对全局进行构建,充当一个指挥者,指挥这个任务由哪个对象来做,那个任务由哪个对象来做,但是每个对象具体怎么做还是要用到面向过程的思维方式来完成。
二、对象和类的关系
1.对象
对象是具体的事物,实例,例如一个杯子就是一个对象
2.类
类就是对象的像的提取,也就是说是对所有对象的相似部分进行提取,组成的一个抽象的概念,例如人就是一个类,它是将很多我们相同的性质的提取
三、局部变量和成员变量的区别
1.局部变量
局部变量定义在方法中的或者定义在代码块中的变量;
局部变量的作用域仅限于该方法内部,或者包含该局部变量的代码块内部;
局部变量在定义时必须要进行变量的初始化赋值,不然在后续方法内部使用时会报错;
局部变量的内存是在栈中;
局部变量的作用时间是从方法执行到结束 ;
2.成员变量
成员变量就是定义在方法外,类里面的变量,是属性;
成员变量的作用域是整个类内部;
成员变量在定义的时候不需要对该成员变量进行初始化赋值,后续使用的时候在进行赋值,因为成员变量有默认值;
成员变量的内存是在堆中;
成员变量作用的时间是从该对象创建到销毁;
四、创建类
类中要有属性(成员变量)、方法
package com.heyanshu1;
/**
* @author: HeJun-Qi
* @data: 2021/7/24 15:58
* @description: com.heyanshu1
* @java_version: 12.0.2
*/
public class object1 {
//创建一个空构造器(必须要有这样一个空构造器)
public object1(){ //一般不会在空构造器中对属性进行初始化赋值,因为那样的话每个对象的属性就一样了
}
//属性
String name;
int age;
double hight;
double weight;
//方法
public void sleep(){
System.out.println("今天随眠质量良好!");
}
}
五、创建对象
-
在完成类的创建后单独创建一个test类,创建类的作用就是为了调用该类中方法
package com.heyanshu1; /** * @author: HeJun-Qi * @data: 2021/7/25 15:30 * @description: com.heyanshu1 * @java_version: 12.0.2 */ public class test1 { public static void main(String[] args) { object1 accept=new object1(); //这里用new来调用方法,不像以前用点来调用 System.out.println(accept.age); System.out.println(accept.name); System.out.println(accept.weight); System.out.println(accept.hight); } }
-
创建一个所需要类的具体的对象/实例/实体
//代码格式:类名 接收、对象在内存空间中开辟的地址名=new 类名 // 例如: object1 p=new object1; //这里的P接收的是创建的对象在空间中的地址,后续中通过这个地址到堆中去找到对应的空间,然后找到对象中的相关属性的值 System.out.println(p.age); System.out.println(p.name); System.out.println(p.hight);
-
在计算机内部创建对象的过程
- 当第一次遇见某个类时,进入类加载器classloader中(只在第一次遇见该类时加载一次,之后再创建对象的时候就不会进入了)
- 加载完成后,创建对象,为这个对象在堆中开辟空间并为创建的对象进行初始化动作(其实在加载完成后对象就已经生成了,所以在进入加载器的时候会有个this,同时在对象创建完成后也随即给对象进行初始化赋值,这里的初始化赋值其实是对类中的属性进行默认的赋值操作)
- 之后进入类中去找构造器
4.new关键字的作用
- 实际上关键字是在调用一个方法,这个方法叫做构造方法(构造器)
- 当我们在调用构造器的时候,如果我们自己没有编写构造器的话,系统会默认给你分配一个构造器,只是我们看不见(系统默认分配的构造器的话debug调试就看不见一步步执行赋值操作,所以我们点下一步就直接退出类,回去执行下一行代码)
- 构造器的作用不是创建对象,因为在调用构造器前就已经在内存中创建好了,并且属性有默认初始化的值
- 调用构造器的作用是对属性进行赋值操作
六、构造器的重载
1.什么是构造器的重载
构造器的重载就是构造器的名称相同,但是形参列表不同的构造器
2.为什么要构造器的重载
因为我们要保证空构造器的存在,又要保证构建的对象的属性值可变
3.构造器的重载需要注意的问题
- 重载构造器的形参名要和对象的属性名一样的话,就必须在属性名前面加上this.前缀,只是因为程序有就近原则,当不指定参数时默认每个参数就是最近的那个参数,这样就会导致在用new调用构造器时我们的形参不能赋值给属性值(这里的this就是我们创建的对象)
- 构造器赋值适用于当对象有多个属性需要进行赋值操作
4.代码展示
1.创建类
package com.heyanshu1;
/**
* @author: HeJun-Qi
* @data: 2021/7/24 15:58
* @description: com.heyanshu1
* @java_version: 12.0.2
*/
public class object1 { //创建object1类
public object1(){ //创建空构造器,不能再里面对属性赋值操作
/*age=19;
name="xiaxia";
hight=165;
weight=96;*/
}
public object1(String name,int age,double weight,double hight){ //创建构造器重载,改变形参的个数
this.age=age; //由于形参名和属性名相同,所以必须在属性名前面加上this.前缀
this.name=name;
this.weight=weight;
this.hight=hight;
}
String name; //定义属性
int age;
double hight;
double weight;
public void sleep(){ //定义方法
System.out.println("今天随眠质量良好!");
}
}
2.创建测试类
package com.heyanshu1;
/**
* @author: HeJun-Qi
* @data: 2021/7/25 15:30
* @description: com.heyanshu1
* @java_version: 12.0.2
*/
public class test1 {
public static void main(String[] args) {
object1 accept=new object1("xiaxia",19,95,167); //这一步在内存中已经创建了对象,new构造器只是对类中属性进行赋值操作。
//在创建对象的时候直接在构造器形参中赋值,不用在使用accept.age=19这种赋值方式
System.out.println(accept.age);
System.out.println(accept.name);
System.out.println(accept.weight);
System.out.println(accept.hight);
}
}
七、创建对象的内存分析
1.创建对象的语句
//例如已经创建了一个hoom类
home p=new home;
2.创建该对象的内存分析
-
通过类加载器加载home类,并将 home .class 字节码文件信息所对应的方法传到方法区,同时在堆中存放字节码信息,根据字节码信息以该方法为模板在堆中创建对象,同时对其进行地址分配和默认初始化赋值
-
通过new关键字在home类中去找构造器
-
找到构造器后将值赋值给属性,,构造器的内存是在栈中开辟的构造器栈帧中,里面有用户需要赋值给属性的值,一般类型数据直接将所需值赋值给形参,引用型数据如string类型的数据,需要将该数据放在方法区中开辟的字符串常量池中,然后将改值对应的地址码传给形参
-
完成属性赋值后,将堆中创建的方法地址赋值给p,栈中为main方法开辟的栈帧,p是该栈帧中的变量
-
后续程序要用到该对象的相关属性的时候可以直接调用p.属性来进行属性的输出
-
在调用p的时候首先通过地址进入堆中找到方法所在的内存空间,然后将需要的属性值调用出来赋值给其他变量
八、this的使用
1. this的含义
- 在创建对象的时候,进入构造器对属性进行赋值前,存在的this指代的是我正在创建的对象,里面有该对象所具备的属性以及默认初始值
- 当在进行调用的时候,存在的this 指代的是当前正在调用的对象
2. this 的用法
-
修饰属性:当构造器中的形参名和属性名相同时,在对属性进行赋值时需要在属性名前面加上this. 来指代名为对象的属性名,(这个this指代的是调用该方法的对象,所以this.就相当于对象.)
public person(){ int gae; String name; double height; public person(){ } public person(int age,String name,double height){ this.age=age; //形参与属性名相同所以需要加上this.来修饰属性名,这里的this是正在创建的对象 this.name=name; //同理这两句也可以用this(age,name) this.height=height; } public person(int age,String name){ this.age=age; //这一句可以用this调用构造器来完成:this(age);表示调用一个参数的构造器 this.name=name; } public person(int age){ this.age=age; } public void play(){ int age=10; System.out.println(age); System.out.println(name); System.out.println(this.age); //局部变量age和属性名相同,所以要加上this.,这个this指代的是调用paly方法的对象 System.out.prinltn("I Like playing basketboll!") } public void sleep(){ System.out.println("睡觉真不错!") } }
-
修饰方法:当一个方法里面的代码和另外一个方法里面的代码有相同的部分时,可以用this调用方法到另外一个方法里,减少另外一个方法中重复写相同的代码(注意当调用方法时,调用语句必须写在最前面)
public void read(){ System.out.println("我喜欢看《小王子》"); System.out.println("我喜欢看《红与黑》"); } public void aiHao(){ System.out.println("我喜欢看《小王子》"); System.out.println("我喜欢看《红与黑》"); //这两句完全可以用:this.read()来代替,只是这里的this.可以省略,因为这两个方法在同一个类中 //这里的this指代的是test类中person p=new person,中的p,相当于在使用p.aiHao这句代码调用aiHao这个方法的时候,先进来执行p.read,执行这句的时候就会跳转到read方法中去,执行完后read后再接着执行aiHao方法后面的内容 System.out.println("我喜欢看电影"); System.out.println("我喜欢打游戏"); }
-
修饰构造器:
public person(){ int gae; String name; double height; public person(){ } public person(int age,String name,double height){ this.age=age; this.name=name; //同理这两句也可以用this(age,name) this.height=height; } public person(int age,String name){ this.age=age; //这一句可以用this调用构造器来完成:this(age);表示调用一个参数的构造器 this.name=name; } public person(int age){ this.age=age; }
九、static 的使用
1. static 在内存中的含义
在创建对象的时候,进行类加载时除了将类的字节码信息加载到方法区外,还有将定义的静态属性放入方法区的静态域中,并进行初始化赋值。放在静态域中的属性被整个类所共享,也就是说整个类中所以的该属性都只能有同一个值,一个对象中更改了静态属性那么所有对象中该属性也跟着变,公用这一个属性
2. static 使用的场景
当方法中有,所有使用该属性的对象,都是一样的值,的时候可以在方法中进行:类名.需要的静态属性名=想要赋的值;
3. static 的使用方法
public class heYanShu(){
static int age;
String name;
double height;
//heYanShu.age=18;不能在这对静态变量age赋值操作
public heYanShu(){
}
public heYanShu(String name,double height){
this.name=name;
this.height=height;
}
public static void main(String[] args){ //要是这里定义的方法不是static类型的话,在调用age这个static修饰的属性的时候会报错,因为static修饰的方法只能直接调用static修饰的方法或者属性
heYanShu.age=18;
heYanShu p1=new heYanShu("xiaohua",182);
System.out.println(p1.name);
System.out.println( heYanShu.age);
System.out.println(p1.height);
heYanShu p2=new heYanShu("xiaoming",176);
System.out.println(p2.name);
System.out.println( heYanShu.age);
System.out.println(p2.height);
}
}
运行结果:两个人都是18岁
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Mc3hXltE-1661865921836)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210728155031105.png)]
如果在属性定义后对静态域变量age进行赋值操作,是在构造器中对age变量进行赋值操作,那么在运行结果中该类中所有age变量的值会是最后一次age变量所赋的值
package com.heyanshu2;
/**
* @author: heYanShu
* @data: 2021/7/28 15:32
* @description: com.heyanshu2
* @java_version: 12.0.2
*/
public class heYanShu {
static int age;
String name;
double height;
public heYanShu(){
}
public heYanShu(String name,double height,int age){
this.name=name;
this.age=age;
this.height=height;
}
public static void main(String[] args) {
heYanShu p1=new heYanShu("xioaming",182,17); //利用构造器对属性进行赋值
// p1.age=17; //调用方法的形式对属性进行赋值
// p1.name="xiaohua";
heYanShu p2=new heYanShu("xiaohua",178,16);
// p2.age=19;
// p2.name="xiaoming";
System.out.println(p1.name);
System.out.println( p1.age);
System.out.println(p2.name);
System.out.println( p2.age);
}
}
输出结果:静态变量age的值是最后一次所赋的值都为16
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WAD0BhMP-1661865921838)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210728160556712.png)]
4. static 修饰属性总结
- static所修饰的属性在类加载的时候一起加入方法区中的静态域中,并赋默认初始值
- 先于对象存在,所以在堆中创造的对象里面没有该属性的地址
- 访问方式:类名.属性名,对象名.属性名
5. static 修饰方法
-
public和static 都是修饰词,没有先后顺序所以可以写成:
public static void main(String[] args){ } //或者 static public void main(Stringp[] args){ }
-
在静态方法中不能访问非静态属性,(在非静态属性前加上this也不行)因为静态方法先于对象产生,而非静态属性是对象所特有的属性
-
在静态方法中不能访问非静态方法,(在非静态方法前加上this 也不行)因为静态方法先于对象(this )产生,非静态方法要用对象去调用,在调用非静态方法的时候可能还没有创建对象
-
static 修饰的方法只能访问static属性和调用static 方法
-
非静态的方法可以用对象名.方法名调用
-
静态方法可以使用对象名.方法名或者类名.方法名
package com.heyanshu3; /** * @author: heYanShu * @data: 2021/7/29 14:20 * @description: com.heyanshu3 * @java_version: 12.0.2 */ public class object1 { //创建object1类 static int age; //创建静态属性age String name; double weight; public object1(){ //创建空构造 } public object1(String name,double weight){ //创建构造器的重载,一般不会将静态属性在构造器里面赋值 this.name=name;//在构造器中对属性进行赋值操作 this.weight=weight; } public void a(){ //创建非静态的方法 System.out.println(age); System.out.println(name); System.out.println(weight); } public static void b(){ //创建静态的方法 // this.a; //在静态方法中不能调用非静态方法 System.out.println(age); // System.out.println(name); //由于在静态方法中调用了非静态属性name,所以报错 // System.out.println(this.name); //在非静态方法中调用了this 关键字所以报错 } public static void main(String[] args) { object1.age=19; object1 person=new object1("heyanshu",110); object1.b(); //调用静态方法的第一种方式(推荐方法) person.b(); //调用静态方法的第二种方式 person.a(); //调用非静态方法的唯一方式 } }
运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-43kpFtqY-1661865921838)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210729151521558.png)]
十、代码块
1.代码块的分类
-
静态块:静态块是指用static 修饰的代码块,外置在方法外、类里面;里面编写的内容是创建工厂,数据库的初始化信息,而且静态块只在类加载的时候执行一次
public class test{ public void a(){ System.out.println("a------"); } //静态块 static{ //内容是创建工厂,数据库的初始化信息 } }
-
构造块:构造块是指在方法外、类里面的代码块,用于将方法里面的代码拿到方法外面执行
public class test{ public void a(){ System.out.println("a------"); System.out.println("b------"); //System.out.println("c------"); } //构造块 { System.out.println("c------"); } }
-
普通块:放在方法里面的代码块,也就是方法的具体逻辑代码
-
同步块(多线程那在详细描述)
2.代码块之间执行的先后顺序
静态块,构造块,构造器,普通块
十一、包和导包
1.包是什么
包就是文件夹,里面可以存放子包和java类文件
2.包的作用
- 包的作用就是解决包或者java类文件的重名问题
- 解决权限问题
3.怎么导包
-
自己创建的包
- 包名必须是小写英文字母
- 包名格式:com.公司名.模块名,中间用.来隔开,每一个点代表一个子目录,例如com.heyanshu.test代表的就是在com目录下的heyanshu目录下的test模块(test模块里面就是.java文件)
- 包名不能是系统关键字,例如nul,com1~com9,con…
- 声明包的位置在非注释性代码的第一行
- 导包格式:new 类名;如果设置了自动导包则会自动导入包,如果没用设置就需要手动导包,格式是:import com.公司名.模块名.类名,这句话就是为了定位类名用的
-
系统自带的包
- 导包格式:new 类名
- 当已经调用了该类,并导入了包,但是想要在其他包里面用同名的类,那么需要自己手动导包
- 在同一个包下的类可以不用导包,直接用,格式:new 类名
- 在java.lang包下的类,使用的时候可以不用导包(Math.random就是该包下的方法)、
- 可以直接导入所有该包里面的所有类,格式;例如impote java.util.*,代表的是将java.util包里面的所有类都导入
4.导包需要注意什么
-
java中的包没有包含和被包含的关系,也就是说当我导入一个包里面的所有类时,在该包下的包含的子包里面的类或者子包并不会导入,如果要用的话,需要自己手动导入,例如:
import com.heyanshu1.*; //将该包下的所有类都导入,不包含该包下的子包 import com.heyanshu1.object1.test1; //这就是上面包的子包,它并没有和上面的包一起导入
-
静态导入:格式:import static java.lang.Math.表示将java.lang下的Math包里面的所有方法导入,如果写成 import java.lang.Math.*表示的是将java包下的lang包下的Math包下的所有类导入
-
在静态导入后,如果同一个类中有与静态导入的方法相同的方法,那么优先走自己定义的方法
5.代码演示
package com.heyanshu.guide_package_test;
import java.util.Date;
import static java.lang.Math.*; //j
/**
* @author: heYanShu
* @data: 2021/7/29 18:24
* @description: com.heyanshu.guide_package_test
* @java_version: 12.0.2
*/
public class test {
public static void main(String[] args) {
new Date();
new java.sql.Date(1000L);
System.out.println(Math.random());
System.out.println(Math.PI);
System.out.println(random());
System.out.println(PI);
System.out.println(round(9.9));
}
public static int round(double b){
return 1000;
}
}
运行结果:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nPaF0Wba-1661865921839)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210730130406501.png)]
十二、final的使用
1、final修饰变量
package com.heyanshu6;
/**
* @author: heYanShu
* @data: 2021/8/6 15:10
* @description: com.heyanshu6
* @java_version: 12.0.2
*/
public class attribute {
public static void main(String[] args) {
//第一种情况:final修饰基本数据类型的变量
final int AGE=10;
//AGE=20; 这里报错因为当被定义的属性变量被final修饰后就不能对其进行修改了,该变量属性就变成了字符常量,一般用大写表示
//第二种情况:final修饰引用数据类型变量
final hys p=new hys(); /*内存分析:在对堆中创建的hys类型的对象,通过引用数据类型的p接收该对象的地址,
通过调用方法m将p传入方法中赋值给形参q,q中现在也是存放的q中的地址,二者都同时指向创建的对象,之后执行方法体,
重新创建一个hys类型的对象,这是由于p被final修饰所以指向的地址只能是第一个创建的对象,但是q可以改变,
现在第二个对象创建完后,q将指向创建的对象,地址也变为该对象的地址*/
m(p);
//第三种情况:final修饰引用数据类型的变量
final hys p2=new hys(); //final修饰引用数据类型变量
n(p2);
}
public static void m(hys q){
q=new hys(); //这里的q的地址可以变化
}
//第三种情况:final修饰引用数据类型的变量
public static void n(final hys q){
//q=new hys(); 这里报错就是因为final修饰了形参q导致其地址值不能更改,必须和输入的引用数据类型的地址一致
}
}
2. final修饰方法和类
package com.heyanshu6;
/**
* @author: heYanShu
* @data: 2021/8/6 15:57
* @description: com.heyanshu6
* @java_version: 12.0.2
*/
public final class method { //当一个类被final修饰,那么就说明该类不能被继承,同时该类中的方法中final也可以省略
public final void shot(){ //final修饰该方法后,该类的子类中不能对该方法进行重写
System.out.println("喊叫");
}
}
package com.heyanshu6;
/**
* @author: heYanShu
* @data: 2021/8/6 15:58
* @description: com.heyanshu6
* @java_version: 12.0.2
*/
public class chilad extends method { //这里报错就是因为继承的这个父类被final修饰,那么该父类不能被继承
@Override
public void shot() { //这里报错由于该方法在父类中用final修饰了,所以不能对该方法进行重写
super.shot();
}
}
3. Math 类与final修饰符间的联系
-
Math类属于java.lang包中,使用的时候不需要进行导包处理,直接使用Math.方法名().[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NkTs4adI-1661865921840)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806170125771.png)]
-
Math类中没有子类,不能被继承,就是因为Math类被final修饰了[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8EFDAk4w-1661865921841)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806170518111.png)]
-
Math类里面的属性都被final修饰,变成了大写的字符常量,所以不能被修改,方法其实也都被final修饰了,不过都省略了,因为Math类已经被final修饰了,方法中的final可以省略不写
-
外界不可创造对象,因为Math类中的空构造器被private修饰了,该构造器自能在Math类中有效,例如:Math m=new Math()都是报错的[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XuyhbLiI-1661865921842)(C:\Users\hejunqi\AppData\Roaming\Typora\typora-user-images\image-20210806171349449.png)]
-
Math类中的所有方法和属性都被static修饰了,所以不用创建对象就能对里面的属性和方法进行调用,(其实想创建对象也不能创建对象,原因如上第4条),调用格式:类名.方法名()
十三、抽象类和抽象方法
1.抽象类和抽象方法的定义:
当父类中定义的方法无论如何都不能满足子类中的需求时,子类中都必须重写方法才行,那么省去父类中的方法体,用abstract修饰该方法,那么这就构成了一个抽象方法,如果一个类中有抽象方法,那么就必须用abstract修饰该类,这个类就是抽象类,同时抽象类中也可以没有抽象方法。
2.抽象类的继承
抽象类可以被其他类继承,继承的类可以通过abstract修饰成为抽象类,但是一般我们通过在子类中重写所有抽象类的抽象方法而不是用abstract来修饰该子类
3. 抽象类的注意事项
-
抽象类不可以创建对象,例如如下错误:
public abstract class person{ //类中有抽象方法必须用abstract来修饰该类,变成一个抽象类 public abstract void see(); //抽象方法省去方法体用abstract来修饰该方法 public abstract void play(); } calss student extends person{ //子类继承抽象类必须重写所有所有抽象方法 public abstract void see(){ //重写方法体 } public abstract void play(){ //重写方法体 } } class test{ public void main(String[] args){ person p=new person();//这里报错因为person类是一个抽象类,不能对他创建对象 student s=new student(); //在子类中创建对象可以 s.see(); s.paly(); } }
-
子类中可以创建对象
-
抽象类不可以被final修饰,因为抽象类创建的目的就是为了给子类提供模板的
-
抽象类中也有构造器,因为在子类中创建对象的时候,会在子类中的构造器第一行执行super,以调用父类中的构造器
4.抽象类和抽象方法的联系
在抽象类中定义抽象方法是为了给子类 提供一个通用的模板,子类可以在此模板基础上进行开发,先重写父类中的抽象方法,然后可以扩展子类的内容,抽象类设计避免了子类设计的随意性,通过抽象类子类设计更加严谨,进行了一定程度上的限制(但是并未限制死,子类中依然可以加入自己的一些东西),使子类更加通用。
5.抽象类不影响多态的写法
任然可以用父类引用指向子类对象:person p=new student();
十四、接口
1.接口的创建
接口是和类同一个层次,不过类用class修饰,接口用interface修饰
public interface mark{ //创建接口
public static final int NUM=100;
public static abstract void play();
public static abstract int age();
}
2. 接口的性质
-
接口中没有构造器
-
接口用interface修饰
-
接口中的属性默认为常量(大写表示),固定修饰符:public static final(可以省略,写了也是灰色字体)
-
接口中的方法默认为抽象方法,固定修饰符;**public abstract **(可以省略,写了也是灰色字体)
-
类和接口的关系是:实现关系,用修饰符implements,就是一个class类实现interface接口(可以是多个interface接口)的功能
-
一个类实现接口必须将接口中的方法(其实是抽象方法)进行重写,实现多少个接口就要对多个接口中的方法全部进行重写,如果
没有将所有方法进行重写,那么就需要在该类前面用abstract修饰,将其转换为抽象类
import java.awt.desktop.ScreenSleepEvent; /** * @author: heYanShu * @data: 2021/8/7 15:21 * @description: PACKAGE_NAME * @java_version: 12.0.2 */ public interface testInterface { //在接口中默认将属性定义为常量,方法定义为抽象方法,所以修饰词都是灰色 public static final int NUM=100; //用final修饰的变量是常量 public abstract void play(); //用abstract修饰的方法是抽象方法 } interface testInterface2{ void sleep(); int age(int age); class student extends person implements testInterface,testInterface2{ //student类继承父类person并用implement修饰符来实现接口testInterface和testInterface2 // 同时必须对接口中的方法进行重写 @Override public void play() { System.out.println("我能打篮球"); } @Override public void sleep() { System.out.println("我能睡觉"); } @Override public int age(int age) { return 19; } @Override public void see() { //由于父类是个抽象类,所以继承就必须重写父类中的方法 } } }
-
一个类只能继承一个直接的父类,但是可以实现多个接口,而且继承关系在实现关系之前
class student extends person implements testInterface,testInterface2{ }
-
接口不能创建对象
-
接口指向实现类(多态)
/** * @author: heYanShu * @data: 2021/8/7 16:59 * @description: PACKAGE_NAME * @java_version: 12.0.2 */ public interface test { //创建接口test int AGE=19; String date(String date); void play(); } class student implements test { //类student实现接口test int age; //test类中自加的属性 double weight; public String date(String date){ //对接口中的date方法进行重写 return "2021/8/7"; } public void play(){ //对接口中的方法play进行重写 System.out.println("我能打羽毛球"); } }
/** * @author: heYanShu * @data: 2021/8/7 17:13 * @description: PACKAGE_NAME * @java_version: 12.0.2 */ public class child { //创建执行类 public void play(test t){ //该类中的方法,形式参数是接口类型的变量t,其实传入的是实现接口test的类所创建的对象,这就是接口引用实现类 t.play(); //这里其实是在调用实现接口的类中的play方法 } }
/** * @author: heYanShu * @data: 2021/8/7 17:10 * @description: PACKAGE_NAME * @java_version: 12.0.2 */ public class test1 { public static void main(String[] args) { test t=new student(); //接口类型的变量t引用实现类创建的对象 child s=new child(); //创建执行者对象 s.play(t); //调用执行者对象中的play对象 } }
-
接口中的常量可以用过接口名.常量名来访问,也可以用实现类.常量名访问,这是因为这些属性都是被static修饰的,所以不需要对象就可以访问,当然也可以通过创建实现类对象,然后用实现类对象.常量名进行访问;还可以通过创建接口引用实现类对象来调用,例如:
testInterface p=new student(); System.out.println(p.NUM);
-
接口中有非抽象方法,用public default 来修饰,当在实现类中重写非抽象方法时,不需要加上default这个修饰符;实现类可以通过直接调用非抽象方法的方法名来调用非抽象方法,也可以通过接口名. super.非抽象方法名来调用非抽象方法
-
接口中有静态方法,用public static来修饰,但是静态方法不可以在实现类中重写,如果重写了,在实现类中也没有重写标志,当在实现类中写了一个和接口中的方法重名的方法的时候,在测试类中调用该方法就会优先调用实现类中的重名方法,若想要调用接口中的方法,就必须用接口名.方法名
-
接口中之所以加入了非抽象方法,是因为如果接口中只用抽象方法的话,那么当接口中修改内容后,对实现类中的影响较大,需要对修改的方法全部进行重写,如果加入了非抽象方法的话,实现类中不会受影响,想调用就调用。
十五、内部类
1.类的组成
类的组成部分:属性,方法,构造器,代码块(静态块,构造块,普通快,同步块),内部类
2.内部类的组成
内部类由成员内部类和局部内部类组成
3.成员内部类
-
成员内部类的位置:方法,构造器,代码块外面,外部内里面,一般只套一层内部类,所以这里的外部类就是我们最开始创建的类
-
成员内部类又分为:静态成员内部类和非静态成员内部类
- 非静态成员内部类里面可以访问外部类的属性和方法,特别注意这里的外部类不同于局部内部类
- 静态成员内部类只能访问外部类中被static修饰的属性和方法
- 外部类不能直接访问成员内部类中的属性和方法,需要通过在外部类中创建内部类的对象,然后通过该对象来调用内部类的属性和方法
- 在成员内部类中访问外部类中的重名属性:外部类名.this.重名属性
- 在内部类中访问内部类中的重名属性:this.重名属性
- 在内部类中访问内部类中的方法中的重名属性:重名属性,因为系统默认就近原则
- 静态成员内部类创建对象:外部类名.静态内部类名 对象名=new 外部类名.静态内部类名()
- 非静态成员内部类中创建对象:先创建外部类的对象a,接着用,外部类名.非静态内部类名 对象名=a.new 非静态内部类名()
- 成员内部类里面可以有属性、方法、构造器等
- 类修饰符:private,default,protect,pubic ,final,abstract
4.局部内部类
-
局部内部类的位置:方法中、构造器、代码块里面
-
方法里面的局部内部类中访问的该方法的变量必须是被final修饰的,也就是说不能对该变量进行修改
-
用接口当作方法的返回值类型,返回的是具体的实现类的对象;
p
实现类中的影响较大,需要对修改的方法全部进行重写,如果加入了非抽象方法的话,实现类中不会受影响,想调用就调用。
十五、内部类
1.类的组成
类的组成部分:属性,方法,构造器,代码块(静态块,构造块,普通快,同步块),内部类
2.内部类的组成
内部类由成员内部类和局部内部类组成
3.成员内部类
-
成员内部类的位置:方法,构造器,代码块外面,外部内里面,一般只套一层内部类,所以这里的外部类就是我们最开始创建的类
-
成员内部类又分为:静态成员内部类和非静态成员内部类
- 非静态成员内部类里面可以访问外部类的属性和方法,特别注意这里的外部类不同于局部内部类
- 静态成员内部类只能访问外部类中被static修饰的属性和方法
- 外部类不能直接访问成员内部类中的属性和方法,需要通过在外部类中创建内部类的对象,然后通过该对象来调用内部类的属性和方法
- 在成员内部类中访问外部类中的重名属性:外部类名.this.重名属性
- 在内部类中访问内部类中的重名属性:this.重名属性
- 在内部类中访问内部类中的方法中的重名属性:重名属性,因为系统默认就近原则
- 静态成员内部类创建对象:外部类名.静态内部类名 对象名=new 外部类名.静态内部类名()
- 非静态成员内部类中创建对象:先创建外部类的对象a,接着用,外部类名.非静态内部类名 对象名=a.new 非静态内部类名()
- 成员内部类里面可以有属性、方法、构造器等
- 类修饰符:private,default,protect,pubic ,final,abstract
4.局部内部类
-
局部内部类的位置:方法中、构造器、代码块里面
-
方法里面的局部内部类中访问的该方法的变量必须是被final修饰的,也就是说不能对该变量进行修改
-
用接口当作方法的返回值类型,返回的是具体的实现类的对象;
p