一、static 翻译为静态的,所有static关键字修饰的都是类相关的,类级别的。
(static相关的有:
【1】静态or实例变量、
【2】静态or实例方法、
【3】静态or实例代码块
【4】静态or实例内部类(这个后面内部类再讲)
二、复习变量的分类:(成员变量和局部变量)
① 在方法体内声明的变量都叫局部变量,都在栈内存(包括引用名)
②在方法体外(类里面方法体外面)声明的变量叫作 成员变量{包含实例变量(在堆内存中)和静态变量(在方法区内存)}
三、static静态变量和实例变量:
1、访问方式:
① 所有static修饰的静态变量,可以采用“类名.”方式或者"引用."访问,包括静态变量访问(方法区)和静态方法(栈)调用
②没有static修饰的实例变量,必须都是通过"引用. " 方式访问,,包括实例变量访问(堆)和实例方法(栈)调用
2、储存位置:存在“方法区内存”。(为类所有对象共享属性)
3、静态变量VS实例变量
1、什么时候用实例和静态变量?
什么时候声明变量(int id)为实例的? 对象级别的特征(每个人都不同的), 声明实例变量 例如名字
什么时候声明变量(static int k)为静态的? 类级别的特征(所有人都一样的特征),声明静态变量 例如中国人国籍
答;如果这个类的所有对象的某个属性值都是一样的,比如(所有中国人的国籍都是中国)
建议定义为静态变量,减少内存占用。 静态变量在方法区只保存一份,节约内存
2、但是static要提前设置好类中的固定的属性,在类中打好static String nationality = “中国”;类似,然后直接去主方法system即可。其他实例变量还是按照构造方法去访问就好。
3、静态是类级别的,实例是对象级别的,因此静态用类调,动态用实例对象调
①实例变量和方法必须只能用“引用.属性名”或者“引用.方法名”方式访问 (同一类中,引用名必须省略或者加this)
②静态变量和方法都可以使用“类名.属性名”或者“类名.方法名”方式访问(同一类中,类名可以省略.)也可以引用. 但是不建议使用引用。会被警告…
四、static静态方法和实例方法:
1、 ①静态方法 (类级别方法) , static关键字修饰的都是类相关的,类级别的,是采用“类名.”方式访问,也不需要new对象,即可访问没有空指针异常的发生。
②非静态方法就是不带static包含(实例方法和构造方法) ,一定要先new对象 才能“引用.”方式访问,也有可能空指针异常。
2、实例方法(对象级别方法):
1、什么是实例方法?(对象级别的)
必须先new对象,然后引用.方法名();方式调用
2、实例方法的语01法结构?参数列表+返回值类型+方法名(){ }
举例为 public(不能有static) void dosome(){}
(不带static的叫做非静态方法包括构造方法和实例方法。带static叫静态方法也就是普通方法)
3、实例方法调用格式(不带static)?(实例变量访问或者方法调用都需要new对象,然后通过对象引用.方式实现。两者不要弄混淆),
实例方法调用——引用名.方法名(); u1.dosome();
在其他类访问实例变量访问——引用名.实例变量名 u1.id(涉及有参传递和无参传递),
在同一类访问实例变量得用this.属性名,或者省略直接访问
演示静态和实例方法:
public class Static概念 {
public static void main(String[]args) {
Test t1 = new Test();
System.out.println(t1.id); //引用调用
System.out.println(Test.no); //类名调用
}
}
class Test{
int id; //实例变量(对象属性)
//以下static关键字修饰的都是类相关的,类级别的,是采用“类名.”方式访问
static int no;//这种static修饰的静态变量。。。。。。。。。。
public void m2() {
// 实例方法。。。构造方法没有返回值。。
System.out.println("实例方法调用了");
}
public static void m1() {
//静态方法就是普通方法
System.out.println("静态方法调用了");
}
}
5、普通静态方法 VS实例方法VS 构造方法调用?
实例方法调用;引用名.方法名();
普通方法调用;类名.方法名();(同一类类名可去掉)
构造方法调用;new 类名();
6、小小自我总结类对象:
一、实例方法,主方法或者静态方法都可以访问实例变量(但都要先new对象)。无参和有参构造方法和getset固定实例方法是用来修改赋值
二、其实无论是什么方法,new方法所在类对象都能用引用点去调用。 但是静态方法和变量是类级别,一般类名直接调即可,否则会被警告。
三、其实new对象去哪里new都无所谓的,只要new哪个类的对象,就说明去哪个类访问他的变量属性或者内部方法
四、实例变量在哪个类都是无所谓的,只要去创建那个类对象就可以使用【引用.属性】进入去访问变量.
五、实例方法在哪个地方调都是无所谓的,只要在方法体里面,注意是类名还是引用调即可. 但是所有的方法归根结底还是要回到主方法去调(只是有调中调),不然不会去访问到的
大概就是this其实是套用实例方法new好的对象,而当前实例方法能被调用肯定new的当前类对象这里是引用
3、什么时候用实例方法,什么时候用静态方法 ???
(归纳:实动起来就不能static静下来了)
1、 总结:
静态是类级别的,实例是对象级别的,
静态用类调,动态用实例对象调
只要是实例类的不管是方法还是变量都要先new对象。
2、实例方法和静态方法的参考标准?
①当这个方法体中,直接访问了实例变量,那么就一定要用实例方法,new对象
②以后开发中,如果是工具类的,那么工具类方法几乎都是静态的,因为功能固定,当工具人
③如果是涉及对象操作类,都是实例为多,需要不断更变对象以及数据。
3、为什么实例方法比如get,set不能加static?(简单来说就是动起来之后就静不下来了)
1、因为动了实例变量就等于有对象参与和触发,就必须不带static,就不是静态的了。要动起来实例起来。所以是实例方法不带static,只要你没对实例变量的属性操作就可以加static,编译器不管你是静态还是实例。
2、反之加了static就是普通静态方法,用类名访问,用类名访问会找不到对象类的。
3、举例下面例子 如果你return是一个0那么可以加static 因为你没动实例变量 id,
而右边的return的id是一个实例变量,因此不能用static方法,因为动起来就不能静态下来。
public static int getId() { return 0; }
public int getId() { return id; }
3、实例方法和静态方法在运行上的区别?!!!!!!
(1)加载时间不同
【1】(实例方法)非静态方法,由于创建时间上的滞后性,有权直接访问静态方法和变量.
(因为静态变量和方法在类加载的时候就被分配内存了,而实例方法在new对象才有内存),就是后加载有权可以访问先加载的,而先加载的无法访问到后加载的(还没创建出来)。/因此new对象是得在类加载完之后才能new。而静态方法这时已经加载出来了。所以实例方法中可以直接访问静态变量)
【2】相反,静态方法中却不能直接访问实例变量和实例方法的原因:(静态方法先于实例类的先加载,所以不能调用一个没加载的方法或者变量
(2)调用的方式不同
【1】静态方法是属于类的,即静态方法是随着类的加载而加载的,在加载类时,程序就会为静态方法分配内存,
【2】非静态方法(实例方法)是属于对象的,对象是在类加载之后创建的,也就是说静态方法先于对象存在,所以对象没创建的话,静态方法自然就不能访问还没创建对象的实例变量
(3)简答来说:
当你创建一个对象时,程序为其在堆中分配内存,一般是通过this指针来指向该当前对象。
对于静态方法,不依赖于对象的调用,它是通过‘类名.静态方法名’这样的方式来调用的。
对于非静态方法,在对象创建的时候程序才会为其分配内存,然后通过类的对象去访问非静态方法。因此在对象未存在时非静态方法也不存在,
静态方法自然不能调用一个不存在的方法。
五、静态代码块和实例代码块(对比着学)
(1)、静态代码块:
使用static关键字,还可以定义:静态代码块
1、 什么是静态代码块,语法结构是什么?
static{
java语句:
java语句:
}
2、什么是实例代码,块语法格式?(非常少用)
{
java语句;
}
3、static静态代码块在什么时候初始化执行呢?
时间:类加载的时候就立即执行,并且在main方法执行之前执行。
作用:在main方法之前执行,可以记录类加载的时间日志
3、实例代码块在什么时候初始化执行呢?
时间: 在new 对象的时候,并且在构造方法执行之前就自动执行 ,
作用:在构造方法之前执行,提取构造方法的重复代码片段,然后放到实例代码块当中,变成公共的代码块,减少内存
4、回顾 静态变量在什么时候初始化 ? 也是类加载的时候执行,存在方法区内存,静态变量是类的所有对象共享的。(比如所有学生对象的国籍)
5、回顾 实例变量实在什么时候初始化?(也就是给默认值),是要在new对象成功后去构造方法里面才会开辟空间来初始化,并存在堆内存
类加载只是给对象一个属性名而已,并不是在类加载时候,赋值实例变量
6、静态代码块执行特点:
1、静态代码块在 类加载创建的时候执行 ,并且在main方法执行之前执行。
2、静态代码块 ,一般是自上而下的顺序执行,可以编写多个静态代码块,但是永远只执行一次。
7、实例代码块执行特点:
1、实例代码块会每次在构造方法执行之前都会执行一次实例代码块
***4、静态代码块有啥作用?***(sun公司给程序员准备的一个类加载时机)
1、(不常用)不是每个类都要写的东西
2、因为他是在main方法入口之前执行,不管静态代码块写在main方法的上面或者下面,都会先执行,代码块结束后才会进入main
因此就是可以在类加载之前做一些准备工作,因为执行一次,所以可以用来“记录时间日志”,记录哪个类是什么时候加载到JVM当中去的
4、实例代码块有什么用?( 就是sun公司给程序员提供一个特殊功能)
1、因为实例代码块会每次在构造方法执行之前都会执行一次实例代码块,因此假如很多实例方法当中的代码片段有很多重复的,那么可以提取构造方法的重复代码片段,放到实例代码块当中,变成公共的代码块,减少内存。
5、执行静态代码块注意点;
1、一定要是只能静态变量才能访问,其他变量都不是在类加载的时候开辟空间的
2、定义变量一定要在访问之前定义好,因为是自上而下执行,注意作用域
A、静态代码块的代码演示
public class 静态代码块执行 {
static int k = 1;
static int n = 10;
int i =111; //i变量是实例变量,是要在new对象成功后去构造方法里面才会开辟空间给予默认值。
static {
// System.out.println(i); 这里直接报错 i实例变量还没初始化,不承认这个值
// System.out.println(name); 这里也是直接报错,因为静态代码块是自上而下进行的,执行到这里之前name还没被定义出来,就被报错,在下面定义没用
}
static String name = "tuyuexin";
static {
System.out.println("k = "+静态代码块执行.k);//这里类名可以省略,静态变量和访问在同一个类中,变量要是在其他就要。类名.访问
}
public static void main(String[]args) {
//主方法是程序入口,但是在此之前可以执行代码
System.out.println("main begin");
System.out.println("k = "+k);
System.out.println("main over");
}
static {
System.out.println("n="+n);
}
}
//执行顺序结果为;
//先执行static静态代码块,最后再去主方法输出
//k = 1
//n=10
//main begin
//k = 1
//main over
/*总结目前遇到过的所有java程序的执行顺序
* 第一,对于一个方法体来说,方法体中的代码是有顺序的,遵循自上而下的执行顺序
* 第二,静态代码块1和静态代码块2是有先后执行是顺序
* 第三、静态代码块和静态变量定义是有先后执行顺序的。
*
*/
B、实例代码块的代码演示:
public class 实例代码块执行 {
public static void main(String[]args){
System.out.println("main begin");
new 实例代码块执行();//调无参
new 实例代码块执行();//调无参
new 实例代码块执行("abc");//这里传参数等于没传,只能单纯地进入方法。因为有参构造那里没有进行参数的传递
new 实例代码块执行("xyz");//即 对象属性名 = 形参名
System.out.println("main over");
}
{
System.out.println("实例代码块执行了");//实例代码块
}
public 实例代码块执行(){
// 可以在自己类调无参构造器,但是一般在别的类调
System.out.println("无参造方法执行了");
}
public 实例代码块执行(String name){
System.out.println("有参造方法执行了");
// 对象属性名 = 形参名 不然不会参数传递
}
}
//执行结果;每次在构造方法执行之前都会执行一次实例代码块。
//main begin
//实例代码块执行了,
//无参造方法执行了
//实例代码块执行了
//无参造方法执行了
//实例代码块执行了
//有参造方法执行了
//实例代码块执行了
//有参造方法执行了
//main over
C、静态和实例代码块的综合执行顺序案例:
先静态代码块——>main方法———>实例代码块————>构造方法
public class 静态和实例代码块综合顺序 {
// 静态代码块
static {
System.out.println("A");
}
public void main(String[]args){
System.out.println("main begin");
new 静态和实例代码块综合顺序();//调无参构造方法
System.out.println("main over");
}
// 无参构造方法
public 静态和实例代码块综合顺序() {
System.out.println("B");
}
// 实例代码块
{
System.out.println("C");
}
// 静态代码块
static {
System.out.println("X");
}
}
//不多讲了,自己理解 就是静态代码块在main之前执行,并且自上而下,
// 实例代码块在构造方法之前执行,但在main之后。,因为要进入构造方法得先进入main
//执行顺序
// A——X——begin——C——B——over。
六、static方法永远不会空指针
1、带static静态方法永远不会空指针,创建了对象也不会。系统会自动识别类级别还是对象级别的方法,然后转换。
2、实例和构造方法会空指针。因为一旦引用为null,引用所指向的堆内存的对象地址就会被回收掉不见了。也就会空指针异常
public class Static不会空指针 {
public static void main(String[]args) {
ChinesePeople c1 = new ChinesePeople("440229","linruiyi");
System.out.println(c1.idCard);
System.out.println(c1.name);
System.out.println(ChinesePeople.nationality);
System.out.println(c1.nationality);//不建议使用,会被警告
c1 = null;
System.out.println(c1.nationality);//没有问题,不会空指针,还是输出中国。因为这个静态变量在方法区内存,所以不会被空指针
System.out.println(c1.idCard);//下面两个全部空指针,因为空指针针对的是堆内存地址,地址没了就没了
System.out.println(c1.name);
}
}
class ChinesePeople{
String idCard;
String name;
static String nationality = "中国";
public ChinesePeople() {
}
public ChinesePeople(String x,String y) {
idCard = x;
name = y;
}
}
第一、this是什么?
【1】通俗点:this其实是套用实例方法已经new好的自身类对象,而当前实例方法能被调用肯定new了的当前类对象
【2】严格来讲:this就是指“当前自身所在类对象”,哪个对象调用实例方法,this就是那个对象
【3】this是一个关键字,一个对象一个this变量?
【4】this其实表示的就是对象类本身。只是会具体对象化,变成当前对象
比如如果对象c1调实例方法那么this就等于c1
如果对象c2调实例方法那么此时this就是c2
以此类推 …
【5】 this为什么一定是指向自身类的实例变量?
因为实例方法能被调用,肯定是先new好了实例方法所在类的对象,(this其实是套用实例方法new好的对象,而当前实例方法能被调用肯定已经new了的当前类对象)
第二、this保存在堆内存当中,具体保存在对象的内存地址当中,并且指向自身类对象
第三、this在大部分情况下是可以省略的。
【1】this.省略的话,是默认访问的是当前对象的name
【2】在实例方法或者构造方法中,为了区分局部变量和实例变量这种情况下this.不能省略
第五、【1】this不能出现静态方法中 :因为类加载的时候没对象还没创建。静态方法不能直接去访问实例变量
【2】this只能出现在 实例方法当中:因为你调用静态方法时不用创建对象,所以this交接不了
【3】this表示当前对象,而静态方法不存在当前对象
第六、那什么时候可以用this?
当实例方法访问自身类的实例变量,可以用this。别前提是的类或者自身类的里面方法里面已经提前new好了对应的类对象,来调用你这个实例方法。那么this就可以借用来当成等于当前的对象。
this其实是套用实例方法new好的对象,而当前实例方法能被调用肯定new的当前类对象
注意:
六、使用this好处:
this为什么只能是方法自身类的对象?
①调用实例方法/变量前提,一定要先new好实例方法所在类的对象,(这样才能引用进入所在类类去找你的实例方法/变量位置) ,之后再去主方法或者其他方法用引用去调用。
②那么这时调用实例方法再去访问方法自身类类的实例变量的时候.就可以直接用this或者省略。因为你能调用实例方法说明你已经已经new好了当前方法所在类对象,
③好处: 因此在当前实例方法中访问该类实例变量的时候就不用了再次new新的类对象了,直接套用已经new好的对象,但是new的对象可能有好几个并且在别的方法中,所以对象引用名作为局部变量出了原来方法的作用域就不能用引用.去访问,因此就要用this,来代替所有的当前对象。
④用this不仅不用改引用名可以访问多个对象,还能跨主方法的引用名作用域。
【1】用this代替了主方法的引用名来表示当前对象
【2】如果你不想用this,我一定要用引用,也行,则需要在当前新的实例方法中new新一个的对象,然后再去赋值访问,不过对象名就固定下来了,每次访问不同的对象都要改引用名。
This基本使用案例1
public class 实例访问用This和用引用的具体例子 {
public static void main(String[]args) {
Student s1 = new Student("tuyuexin");
Student s2 = new Student("linruiyi");
s1.doit();
s2.doit();
}
}
class Student{
//非静态方法由于创建时间的滞后性,有权直接访问静态方法和变量。
String username ;
static String name ="lisi ";
public Student() {
}
public Student(String username) {
this.username = username;
}
public void doit(){
System.out.println(Student.name+"正在嘿嘿嘿");//因为是静态变量,可以直接访问,同一类类名可以省略
System.out.println(this.username +"正在啪啪啪"); //实例方法访问当前类对象,套用访问实例方法时已经new好的对象。可以跨作用域访问多个对象前提每个对象都调用一次该实例方法,
Student s3 = new Student(); //实在不想用this也行,可以重新当场new一个新对象,用引用方式访问。但仅限于s3。并且不能跨s3对象的作用域
s3.username = "nihao";
System.out.println(s3.username);
}
}
类封装私有化后This的变化?
* 为什么发生了?
* 当子类继承了父类的全部东西之后,再去访问private私有实例变量?
* (就不能直接去访问实例私有变量了,虽然继承了,但是私有属性特性是出了自身类就无法被访问)
*
* 那么具体操作怎么变?(把所有的私有属性(包括构造方法体和访问实例变量都要改),都改成去调用get属性名方法去返回实例私有属性。因为方法可以被调用)
* 具体就是通过this.调用封装的get+属性名方法来返回一个实例变量,间接访问了实例变量 。举两个例子
*
* 原来是--public Chinese(String name) {
有参构造也要变,只要出现了私有属性,出了自身类都要变,不能直接访问了,后面这里可以用super();
this.name = name;
}
* 现在是--public Chinese(String name) {
this.getName();
}
* 原来是-- System.out.println(this.year + "年" + this.month + "月" + this.day +"日"); //访问实例变量也要变
* 现在是--System.out.println(this.getYear() + "年" + this.getMonth() + "月" + this.getDay() +"日");
*/
public class 继承和覆盖重之后This的变化 {
public static void main(String[]args) {
People p1 = new People(); //这里写了构造方法,所以people可以写有参构造的参数
p1.setName("人");
p1.speak(); //最简单的一访多this方法
Chinese c1 = new Chinese(); //因为构造方法不能被继承,所以chinese这里不能写有参构造的参数,不然报错,只能通过setname来赋值,或者重新再chinese构造一个方法就可以写了
c1.setName("中国人");
c1.speak();
Foreigner f1 = new Foreigner();//同12行 ,没有构造方法,因为父类的构造方法没有继承
f1.setName("外国人");
f1.speak();
}
}
class People{
//父类(人)
private String name;
public People() {
//无参
}
public People(String name) {
//有参
this.name = name;
}
public void setName(String name) {
//封装name
this.name = name;
}
public String getName() {
return this.name;
}
public void speak() {
System.out.println(this.name+"正在说话"); //两种方法访问变量,一种直接访问属性值
System.out.println(this.getName()+"正在说话");//另一种调用getName方法,一样的里面也是返回一个属性值。
}
}
class Chinese extends People{
//中国说汉语
public Chinese() {
}
public Chinese(String name) {
// this.name = name; 这里这么写构造方法也是错误的。因为私有化属性一旦出了自身类就不能被访问。继承之后也一样,只能调get方法去访问变量,看下一行。
this.getName();
}
public void speak() {
//超级重点
// System.out.println(this.name+"正在说话"); 直接报错, 因为私有化属性一旦出了自身类就不能被访问。只能调get方法去访问变量
System.out.println(this.getName()+"正在汉语");//覆盖重写父类的speak实例方法
}
}
class Foreigner extends People{
//外国人说英语
public void speak() {
//超级重点
// System.out.println(this.name+"正在说话"); 直接报错, 因为私有化属性一旦出了自身类就不能被访问。继承之后也一样,只能调get方法去访问变量
System.out.println(this.getName()+"speak English");//覆盖重写父类的speak实例方法
}
}
This综合案例1
package this案例;
/*通过代码封装,实现如下要求。
* 编写一个Book类,代表教材
* 1、具有如下属性;名称(title),页数(pageNum)
* 2、其中页数不能少于200,否侧输出错误信息,赋予默认值200(在要有参和封装方法都要拦截一次,因为都要使用到) 构造方法用来基本赋值的,而封装用来修改和取值。
* 3、为各属性提供赋值和取值方法;
* 4、具有方法;detail,用来在控制台输出每本教材的名称和页数。(在对象用的detail实例方法和this,一访多,直接用getset输出也行,但是要多写很多行代码)
* 一般,创建对象在main主方法,然后访问可以调用在属性对象类的实例方法里,这样用this一访多
* 5、编写测试类BookTest进行测试,为Book类对象属性赋予初始值,并且调用Book对象的detail方法
*/
public class BookTest {
public static void main(String[]args) {
//主方法用来测试
Book b1 = new Book("Java从入门到入土",500);//有参先写出默认数据
b1.detail();//再调用detail实例方法来输出
Book b2 = new Book("Java从入门到秃头",1000);
b2.detail();
//修改赋值
// b1.title = Java高阶;这里直接访问报错,因为已经封装了,出了对象类就无法访问,必须通过setget方法
// b1.pageNum = 500;
b1.setTitle("Java高阶");
b1.setPageNum(100); //必须通过get,set方法
b1.detail();
}
}
class Book{
private String title; //属性属性私有化
private int pageNum; //
public Book() {
}
public Book(String s,int i) {
title = s;
if(i < 200) {
System.out.println("本书页数不能少于200页,,少于200时,默认页数为200页");
pageNum = 200;
return; //如果没上面的赋予200默认值,必须记得要return结束方法,不然会依然会输出下面的赋值,不能继续赋值,返回去继续让用户重写页数,或者在这里给个最低修改值
}
pageNum = i; //这里等于if else
}
public void setTitle(String s) {
//提供入口setget实例方法封装title
title = s;
}
public String getTitle() {
return title;
}
public void setPageNum(int i) {
//setget实例方法封装pageNum
if(i < 200) {
System.out.println("本书页数不能少于200页,,少于200时,默认页数为200页");
pageNum = 200; //题目要求要小于200时修改为默认值200
return; //如果没上面的赋予200默认值,必须记得要return,不然会依然会输出下面的赋值,不能继续赋值,返回去继续让用户重写页数
}
pageNum = i;//程序能执行到这里说明页数肯定大于200
}
public int getPageNum() {
return pageNum;
}
public void detail() {
//总打印方法;因为detail是访问的实例变量title因此,必须是实例方法。
System.out.println("教材名称:"+ this.title +" ,教材页数:" + this.pageNum ); //实例方法访问自身类的属性,用this,一访多
}
}
This综合案例2
public class 丈夫和妻子引用地址案例 {
public static void main(String[]args) {
Husband h = new Husband("123456","张三","1999", null); //丈夫信息 ,老婆还没new出来,只能为null,不然绿了
Wife w = new Wife("456789","张丽","2001",null); //妻子信息,老公还没new出来,只能为null,不然绿了
h.wife = w; //给丈夫的妻子属性赋值
w.husband = h; //给妻子的丈夫属性赋值
//这样丈夫妻子两人产生关系了,互相引用对方信息。来构成夫妻关系
//如果不写这两行,就会变成null空指针异常。
// System.out.println(h.name + "的妻子是" + w.name);这样写是错误的。丈夫和妻子之间没有关联性
System.out.println(h.name+"的妻子是"+h.wife.name); //这样输出才有关联性,直接输出w.name没有关联性,要通过丈夫去找到妻子
System.out.println(w.name+"的丈夫是"+w.husband.name); //同上
}
}
class Husband{
String idCard;
String name;
String birthday;
Wife wife; //引用地址
public Husband() {
}
public Husband(String idCard, String name, String birthday, Wife wife) {
this.idCard = idCard;
this.name = name;
this.birthday = birthday;
this.wife = wife;
}
}
class Wife{
String idCard;
String name;
String birthday;
Husband husband; //同为引用地址。
public Wife() {
}
public Wife(String idCard, String name, String birthday, Husband husband) {
this.idCard = idCard;
this.name = name;
this.birthday = birthday;
this.husband = husband;
}
}
1、
①super. 和 this. (一个调当前this的父类,一个指向当前自身类)
②super();和this();都只出现在构造方法当中。
无参有参构造里面有默认有属性的默认值或者手动值的。
一看到super();方法立马想调用父类的构造方法,并赋值给父类属性。
一看到this();方法立马想调用自身类的构造方法,并赋值给给自身属性。
③super();和this();不能共存,都只能出现在构造方法第一行。有this();的话在第一行,默认的super();就没了。
④但是this()只能出现一次,super()可以两次(无参和有参)。
⑤调构造方法有两种方法目前:
1、用this();自己/super();父类
2、在new对象那里赋值和调用即可 new 类名(xxx,xxx); 然后输出即可
第一、 详解this:
this只能出现在实例方法和构造方法中,this不能使用在静态方法中
this的语法分别有是this.和this();
1、this.用于访问自身类实例变量和方法的时候。
this.在大部分情况可以省略,在区分局部和实例变量的时候则不能省略。例如
public Chinese(String name) {
this.name = name;
}
2、this(); 用于当前的构造方法去调用“本类”中的无参构造方法。目的:代码复用。
this();只能出现在构造方法的第一行,并且只能出现一次。
this(xxx); 则用于当前的构造方法去调用“本类”中的有参构造方法,还可以在new对象那里调有参构造方法。
this(xxx,xxx)
this(xxx,xxx,xxx)
这三种构成方法重载机制,找到对应的“本类”中的构造方法参数类型,个数,顺序 要一致
第二、详解 super:
super也只能出现在实例和构造方法中,super也不能使用在静态方法中
super的语法分别有是super.和super();
1、super.用于访问父类的实例变量和方法的时候。
super.在大部分情况可以省略,
super.什么情况不能省略?(后面讲)
2、 super();用于当前的构造方法去调用“父类”中的构造方法。目的;在创建子类对象时候,先初始化父类型的属性特征,即给父类属性先赋值。
super();也只能出现在构造方法第一行,但可以出现多次 。
3、 super()分为两种。
①super(无参);
【1】(调父类无参构造,前提父类一定要有默认或者手打的无参构造方法)
【2】就是每个子类的无参或者有参构造方法第一行什么都没写的话只会,默认会有一个无参的super();去调用父类的无参构造方法。
【3】如果你想通过有参去调父类的属性,就必须手动打一个有参的super(xxx);才能去调用父类的有参构造方法,不然还是默认调super();父类的无参方法!!!
②super(xxx);
super(xxx,xxx);
super(xxx,xxx,xxx);
【1】( 调父类有参构造,还可以在new对象那里调有参构造方法,前提也是父类一定要有有参构造、子和父的有参构造的参数类型,个数,顺序 要一致)
【2】以上这三种构成方法重载,找到子和父的有参构造的参数类型,个数,顺序要一致
【3】就是每个子类的有参构造方法第一行什么都没写的话,你又想通过有参去调父类的属性,就必须手动打一个有参的super(xxx);才能去调用父类的有参构造方法,不然还是默认调super();父类的无参方法!!!
{this子类对象 [super父类特征(object)] } 一层包一层关系 this向上super super向上object
①super 代表的是 当前对象(this) 的父类型特征,也包含在this当前对象的内部,属于this对象的一部分一块空间
①当一个构造方法第一行,既没有this()也没有super()的时候,默认会有一个super();表示通过当前子类(无参或有参)构造方法去调用父类的无参构造方法,因此必须保证父类的无参数构造方法是存在的。
② 建议每一个类都手动自己把无参构造方法打出来,
虽然系统会默认提供缺省构造器,但是一旦你手打了有参构造系统就不会再默认提供,如果此时你又忘了手动打无参构造,则用super()会报错。会影响后面子类方法的构建
第四、总结super和this的异同:
【1】①super(参数):调用基类中的某一个构造函数(应该为构造函数中的第一条语句)
②this(参数):调用本类中另一种形成的构造函数(应该为构造函数中的第一条语句)
【2】①super: 它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参)
②this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名)
【3】调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
【4】super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
【5】super()和this()均需放在构造方法内第一行。
【6】尽管可以用this调用一个构造器,但却不能调用两个。
【7】this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
【8】this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
super. 什么时候不能省略案例1:
(无参有参构造里面都是带有属性默认值的)
1、回答:想在子类赋值和访问回父类的同名属性。(因为子类允许重复写父类的同名属性,因此系统会把父类继承过来的同名属性给覆盖掉,为了区分就必须使用super和this区别)
2、前提1、一定是得要子和父类的同名属性!!!!
3、前提2、子类的构造方法一定要写好super(name);这样就能在子类赋值时跳去给父类的同名属性赋值。
4、最后在子类super.同名属性名—> 就能访问回去父类了,否则super其实正常就是访问子类从父类继承过来的非同名属性,那样可以省略super了
package super初步;
/* 1、首先普及子类和父类的同名属性概念?
* ①复习:继承除构造方法都继承,覆盖只针对方法。
* ②Java中可以允许子类和父类有共同的变量属性声明。但被继承过来的父类属性名一般都是不写的,默认有,不然会报错的重复声明。
* ③如果子类一旦出现同名属性则父类属性的会被覆盖掉,那么子类的this.优先就近原则访问自身类的同名属性。
* ④那么java是怎么区别子类和父类的同名属性的,就要使用this.name和super.name。
*2、那么怎么在子类赋值和访问父类的同名属性呢?
* ①这时候就不能省略super,需要在构造方法中使用到super(同名属性或者同样的方法(比如覆盖方法),即在子类有,父类也有,子类如果又想要访问父类的同名属性,则super.不能省略。)
* ②this.name和super.name: 此时两个同名属性已经完全分道扬镳,各毫不相关,各自类的实例变量对象,只是属性名字一样, 并且前缀this和super不能省略。用来分别区分子和父的同名属性对象
*/
public class Super什么时候不能省略 {
public static void main(String[]args) {
Vip v = new Vip("VIP张三"); //子类有参
v.shopping(); //子类特有方法
Customer c1 = new Customer("顾客一号"); //父类有参
c1.dosome(); //父类Customer的方法
}
}
class Customer{
//默认有一个父类的String name;
String name; //子类同名name属性
public Customer(){
}
public Customer(String name){
this.name = name;
}
public void dosome() {
System.out.println(this.name+"正在购物");//这里的this指向Customer类的引用c1
// System.out.println(super.name+"正在购物"); //super是指向Object的引用
//这里报错,因为父类的super是父类Customer的父类老祖宗object里面,但是里面没有定义name属性,直接报错
System.out.println(name+"正在购物");//省略了this,实际也是指向引用c1
}
}
//java是怎么区别子类和父类的同名属性的,
//就靠this.name和super.name
class Vip extends Customer{
//String name; //被继承过来的父类属性名一般都是不写的,默认有,因为java中可以允许子类和父类有共同的变量属性声明。
String name; //因此一旦子和父类出现同名属性则父类的会被覆盖掉,那么this.优先就近原则访问自身类子类的同名属性。
//如果没有继承关系,只是单单this,则只能是访问自身类的实例变量或者方法的时候。
public Vip(){
//如果继承关系下,只是父有子没有具体声明出来的属性,那么在子类访问该属性的话this.和super.或者省略,都代表的是父类的属性。因为继承了,但是默认不写的。
//如果在继承关系下,子和父又有具体敲出来的同名属性,那么在子类访问该同名属性的话,则this只能代表当前类同名属性,super代表父类的同名属性。并且不能省略。分别区分子和父的同名属性
}
public Vip(String name){
//跟着name变量走,追踪到源头看name去哪了。
super(name); //如果想要在VIP子类访问父类Customer的name属性,super(name)就不能省略
//子类有参构造,实际是去调用父类的有参构造,并给父属性赋值。
//VIP张三,赋值过来name这里跟着super跑去给赋值父类了,剩下this.name没有赋值的
//因此这里默认有: this.name =null;
}
public void shopping() {
System.out.println(this.name+"正在购物");//,null正在购物
//这里this指向VIP类的引用的v,但是进入构造方法却发现VIP构造方法是super()跳去调用父类Customer的构造方法给Customer赋值的,
//没有给VIP自己类赋值,因此这里的this.name是没有被name赋值的,为null。
System.out.println(name+"正在购物"); //同理第一个
System.out.println(super.name+"正在购物");//张三正在购物
//为什么是为VIP张三,因为程序先进入VIP的构造方法,然后super(name)就是跳去父类给父类Customer的name赋值为VIP张三的
//这里的super指向父类Customer,而Customer类有参构造方法是正常的,因此直接super赋值父类的name为:VIP张三。
}
}
//null正在购物
//null正在购物
//VIP张三正在购物
//顾客一号正在购物
//顾客一号正在购物
1、如果子类不是访问父类的同名属性的话,会怎么样?
后果就是:那么子类访问name属性时,this和super都其实是一样的,可以省略了,因为都是访问的父类继承过来的属性,这时super没啥用了,可省略。
举例:
public class Super概念VSthis {
public static void main(String[]args) {
new B1();//调用B的无参构造方法
new B1(100);//调用B的有参构造方法
}
}
class A1{
int k;
String name = "张三";
public A1(){
//默认
//int k = 0
//String name = "张三";
System.out.println("父类A1的无参构造方法execute");
}
public A1(int k) {
this.k = k;
//String name = "张三";
System.out.println("父类A1的有参构造方法execute");
}
}
class B1 extends A1{
//int k; 默认继承
//String name = "张三"; 默认继承
int k = 100;
public B1() {
// this(123);调用本类的有参构造。
super();//这里默认会有这一行,不写也行,前提父类一定有缺省构造器。
//super()子类调用了父类的属性特征过来。(里面有父类的属性默认赋值)
System.out.println("子类B1的无参构造方法execute");
System.out.println(name);//张三
System.out.println(this.name);//张三
System.out.println(super.name);//张三
//因为子类没有同名属性写出来,这里的三个name属性都是默认通过super()继承父类的name过来了,因此都是一样的,那么this和super就都可省略了,都是去访问从父类继承过来的name属性。都是张三。
}
public B1(int k) {
// this();调用本来无参构造
super(k);//这里调用父类有参构造,给A父类的k赋值了而不是给子类B的k赋值。
System.out.println("子类B1的有参构造方法execute");
System.out.println(this.k);//100,访问本类中的实例变量k,本来是默认值0的,因此没有this.k = k赋值,但是有已经给了默认值100
System.out.println(super.k);//100,访问赋值给父类的实例变量k100
System.out.println(this.name);
//无同名属性,都是调用父类继承过来的name,因此this和super都是张三
System.out.println(super.name);//张三
}
}
//结果;
//父类A的无参构造方法execute
//子类B的无参构造方法execute
//张三
//张三
//张三
//父类A的有参构造方法execute
//子类B的有参构造方法execute
//100
//100
//张三
//张三
2、如果子类构造方法正常写,不写super(有参);会怎么样?
【1】、后果就是:父类super.name为null了,只会给子类自己赋值了。
也就无法通过子类赋值给父类属性了。
【2】、因此遇到同名属性时,子类构造方法一定要准确写好super(有参)。不然super就失效了,除非父类提前设置了默认值,否则就只能给父类的同名属性给予默认值。
public class Super什么时候不能省略 {
public static void main(String[]args) {
Vip v = new Vip("VIP张三"); //子类有参
v.shopping(); //子类特有方法
Customer c1 = new Customer("顾客一号"); //父类有参
c1.dosome(); //父类Customer的方法
}
}
class Customer{
String name;
public Customer(){
}
public Customer(String name){
this.name = name;
}
public void dosome() {
System.out.println(this.name+"正在购物");//这里的this指向Customer类的引用c1
// System.out.println(super.name+"正在购物"); //super是指向Object的引用
//这里报错,因为父类的super是父类Customer的父类老祖宗object里面,但是里面没有定义name属性,直接报错
System.out.println(name+"正在购物");//省略了this,实际也是指向引用c1
}
}
//java是怎么区别子类和父类的同名属性的,
//就靠this.name和super.name
class Vip extends Customer{
//String name;
String name;
public Vip(){
}
public Vip(String name){
//如果第一行写了东西,则系统不会默认有super();
this.name = name;//正常写子类的构造方法,
//后果就是:父类super.name为null了,只会给子类自己赋值了。
}
public void shopping() {
System.out.println(this.name+"正在购物");//
System.out.println(name+"正在购物"); //同理第一个
System.out.println(super.name+"正在购物");//失效变为null了,压根没去父类赋值
//也就无法通过子类赋值和访问到父类属性了。
}
}
3、如果子类构造方法正常写,同时写super(有参);会怎么样?
子类和父类都能访问到。
public class Super什么时候不能省略 {
public static void main(String[]args) {
Vip v = new Vip("VIP张三"); //子类有参
v.shopping(); //子类特有方法
Customer c1 = new Customer("顾客一号"); //父类有参
c1.dosome(); //父类Customer的方法
}
}
class Customer{
String name;
public Customer(){
}
public Customer(String name){
this.name = name;
}
public void dosome() {
System.out.println(this.name+"正在购物");//这里的this指向Customer类的引用c1
// System.out.println(super.name+"正在购物"); //super是指向Object的引用
//这里报错,因为父类的super是父类Customer的父类老祖宗object里面,但是里面没有定义name属性,直接报错
System.out.println(name+"正在购物");//省略了this,实际也是指向引用c1
}
}
//java是怎么区别子类和父类的同名属性的,
//就靠this.name和super.name
class Vip extends Customer{
//String name;
String name;
public Vip(){
}
public Vip(String name){
super(name);
this.name = name;
}
public void shopping() {
System.out.println(this.name+"正在购物");
System.out.println(name+"正在购物"); //同理第一个
System.out.println(super.name+"正在购物");
VIP张三正在购物
VIP张三正在购物
VIP张三正在购物
顾客一号正在购物
顾客一号正在购物
}
}
Super实参用法和子类如何访问父类的私有变量案例?
public class Super实参用法和子类如何访问父类的私有变量 {
public static void main(String[]args) {
Account1 a1 = new Account1();//new父类
a1.setActno("张三");
a1.setBalance(2000);
System.out.println(a1.getActno());
System.out.println(a1.getBalance());
CreditAccount1 c1 = new CreditAccount1();//new子类 //代码过于臃肿,两个账户类的String actno ,double balance属性是一样的,因此可以用继承
c1.setActno("李四");
c1.setBalance(5000);
c1.setCredit(100);
System.out.println(c1.getActno()+c1.getBalance()+c1.getCredit() ); //一种是直接在主方法,用引用调get方法
c1.setActno("tuyuexin");
c1.setBalance(10000);
c1.setCredit(99);
c1.dosome(); //一种是调对象类的实例方法,然后进去dosome实例方法用this.get方法访问实例变量
}
}
class Account1{
//账户类
private String actno; //账户名
private double balance;//余额
public Account1() {
//无参
}
public Account1(String actno,double balance) {
//有参
this.actno = actno;
this.balance = balance;
}
public void setActno(String actno) {
//封装actno
this.actno = actno;
}
public String getActno() {
return actno;
}
public void setBalance(double balance) {
//封装balance
this.balance = balance;
}
public double getBalance() {
return balance;
}
}
//信用账户 //把CreditAccount看成是Account的子类,然后把其重复的属性在子类中省去,跳过不写,只写不重复的属性。
class CreditAccount1 extends Account1{
//子类信用卡账户继承父类普通账户,出了构造方法,其他都是会继承过来的。
//private String actno ; // 账户名
// private double balance;// 余额 直接不写重复的属性,继承过来即可
private double credit; // 信誉值
public CreditAccount1( ) {
//无参
}
public CreditAccount1(String actno,double balance) {
//有参
//this.actno = actno; 报错
//this.balance = balance; 报错
}
public CreditAccount1(String actno,double balance,double credit) {
//有参
// this.actno = actno; 直接报错 ,因为private actno出了自身类不能再用this访问 要写this.getActno();或者 在构造方法系统是自带的super();
// this.balance = balance; 直接报错, 因为private balance出了自身类不能再用this访问 要写this.getBalance ();或者 在构造方法系统是自带的super();
// super.actno = "123"; 一样直接报错,因为虽然super可以调父类的实例变量,但是actno为private。无权跨类访问,一样不行。
// super.balance = 1000.0; 一样直接报错,因为虽然super可以调父类的实例变量,但是balance为private。无权限跨类访问。一样不行。
// this(actno,balance); // 虽然不会直接报错,调自身子其他有参类构造方法,但是一样不能访问从父类继承过来的私有属性。
// super();这里是省略了一个super去调父类的无参构造,因此我们可以用第一种的方法,用super(xxx,xxx);去调父类的有参构造里面的私有属性。
super(actno,balance);//①第一种、可以用super(xxx,xxx);间接调用父类的有参方法,初始化父类属性。但是类型个数和顺序必须和父类一致。看30行
super.getActno(); //第二种、分批super调get方法也可以,因为父类已经有可以调。
super.getBalance();
this.getActno(); //第三种、分批this调自身类get方法也可以,因为封装setget可以从父类继承过来。
this.getBalance();
this.credit = credit; //只有本类定义的私有变量,才能用这种this.属性名访问
}
public void setCredit(double credit) {
//封装credit
this.credit = credit;
}
public double getCredit() {
return credit;
}
public void dosome(){
System.out.println("姓名:"+this.getActno()+" "+"余额;"+this.getBalance()+" "+"信誉值;"+this.credit);//不能写this.balance和this.actno。priavte出了类之后不能再访问,只能调get方法
} //但是可以写this.credit,因为credit在本类。
public void doit() {
System.out.println(this.getActno());
}
}
super终极套娃案例理解。!!!!!!
理解好,super基本就学明白了。大家伙奥利给!
//总结果13654.。。。。。。。。自己理解。。。。。。。不会的话看老杜307集
//在java语言中,不管new什么对象,最后老祖宗的object类的无参构造方法一定会执行。处于栈顶部,最后调用,最先执行。后进先出原则
//虽然是13654 但是其实1前面class A 也继承的object里面的无参构造,只是object的无参构造里面没有输出方法而已,所以哦们看不到里面的东西。
//因此 最严谨的顺序是;Object无参构造+1+3+6+5+4; Object已经是老祖宗根部,里面没有super了
public class Super套娃案例理解 {
public static void main(String[]args) {
new C();
}
}
class A{
public A() {
System.out.println("A的无参构造执行");//1
}
}
class B extends A{
public B() {
System.out.println("B的无参构造执行");//2
}
public B(String name) {
//super();默认
System.out.println("B的有参构造执行String");//3
}
public B(String name,int age) {
//super();默认
System.out.println("B的有参构造执行String");//3
}
}
class C extends B{
public C() {
// this(name);//报错,你想要传一个变量,前提一定要先声明,否则只能传实参。
this("zhangsan");//这个无参构造方法作用域内和形参列表内没有声明name变量,因此只能传一个对应类型个数一致方法重载的public C(String name){}的形参列表中的String类型实参。
System.out.println("C的无参构造执行");//4
}
public C(String name) {
this(name,111);//这里为什么可以传name和111。因为这个有参构造的形参列表声明了String name,因此name声明可以作为一个String类型变量name在该作用域内使用,并且与被调方法类型个数一只,
System.out.println("C的有参构造执行String");//5 //注意这里的38和39的name和被调方法42行的String name没有任何关系,只是重名了而已 。传实参的声明和被调方法的形参名没有一点关系。
//43行写name01都行,只是44行super(name)也要改
} //同理没有声明int类型,因此只能传实参111,才能方法重载去调用public C(String name,int age)
public C(String name,int age) {
super(name);// 声明了name,可以用name。找父类对应的public B(String name)
System.out.println("C的有参构造执行String,int");//6
}
}
final:
1、final是java语言中的一个关键字。
2、final表示;最终的,不可变的(修饰的东西不能变)
3、final+修饰的局部变量?
final 修饰的局部变量,只能赋值一次,不能修改。
4、final+修饰的引用(引用虽然也是局部变量)?
final修饰引用之后无法重新再次new对象,重复的对象也不行,但是可以修改里面具体赋值。
因为final永远只能指向一个对象分配一块空间,因此针对的是对象而不是对象里面的赋值。
不能final A a = new A(“zhangsan”);
a = new A(“zhangsan”); //这里无法重新再次new对象值分配堆内存空间,重复的也不行
a.name = “lisi” //但是可以修改赋值
5、final+实例变量怎么访问呢? (两种方法访问,推荐第一种)
实例变量没有final修饰的话,系统会自动给默认值,可以直接访问
①但是final修饰实例变量了之后,必须在声明的时候就要手动赋值。(强烈推荐)
②(强行直接写属性也行然后,只要赶在系统在赋默认值之前赋值就可以,即就要在无参或者有参构造方法里面手动【this.属性名】赋值。但是必须每个构造方法都要赋值一次。。。因为系统会在每个构造方法里面赋值。(不推荐这种方法)
6、final +修饰的常量?
①常量一般是public公开静态的
②常量的语法结构;public static +final +类型+常量名(单词全部大写,单词之间用下划线连接) = 常量(固定的字面值)
③final修饰的实例变量说明了 该实例变量不会随着对象的改变而改变,这样这样就和static一样了,
因此final+实例变量前面通常会加static静态变量一起修饰为常量。
public static final String COUNTRY = “中国”;
④常量和静态变量的区别?
【1】不同点 :
常量声明后固定死了不能再次修改,静态还能再次修改的。
【2】相同点:
1、静态变量和常量都是类级别的特征(所有人对象都一样的特征),声明为静态变量 例如中国人的国籍
2、 常量和静态变量都是存储在方法区内存,减少内存的占用。
4、final修饰的方法?
final修饰的方法无法被继承inheritance和重写overwrite 反过来子类方法写final父类没写。这没有一点影响,这只能说明子类那个方法不能再次被继承和重写
5、final修饰的类?!!!!
final修饰的类无法被继承。
6、抽象类abstract不能和final组合,这两个关键字是完全对立的。 一起修饰就是非法组合。编译会直接报错
原因:final修饰的类不能被继承,但是抽象类的意义就是被继承。因此为非法组合
7、《总结重点》
①final这个关键字,不管你原来的东西能不能调用或者访问的权限问题。
②final只管你当前这个东西之后是怎么样的,是无法改变的,无法被继承的,最后的。
public class Fianl用法 {
public static void main(String[]args) {
final int i = 10;
// i = 100; //报错final之后局部变量无法重新修改赋值
final A a = new A("zhangsan");
// a = new A("zhangsan"); //报错final引用之后无法重新再次new对象,重复的也不行,但是可以修改里面具体赋值。
a.id = 1234; //但是可以修改对象里面具体赋值
a.dosome();
System.out.println(i);
System.out.println(a.id);
System.out.println(a.name);
}
}
class A{
String name;
int id;
final int age = 18;//必须在声明的时候就要手动赋值,不然报错
final double score; //直接写属性也行然后,只要赶在系统在赋默认值之前赋值就可以,因此可以在每个构造方法里面赋值。
static int num = 1000;//静态变量,可以修改的
public static final String COUNTRY = "中国";//不可以再次修改
public A() {
this.score = 100;
}
public A(String name) {
//参构方法形成了方法重载,对应好方法形参列表的数据类型、个数、顺序;
this.name = name;
this.score = 100;
}
public A(String name,int id) {
this.name = name;
this.id = id;
this.score = 100;
}
public void dosome() {
num = 1001;//静态可以再次修改
System.out.println(num);
// COUNTRY = "美国"; 常量不可再次修改
System.out.println(COUNTRY);
}
}
class B extends A{
public B(){
}
public B(int i ){
}
}
1、什么是抽象类?
类和类之间也有共同特征叫抽象类,这些共同特征抽取出来形成一个类名就是“抽象类”,比如信用卡和储蓄卡的抽象类就是银行卡。
Ps:对象和对象的共同特征叫静态变量
2、抽象类属于什么类型?
属于引用数据类型
3、语法结构?(抽象类)
【修饰符列表】+abstract+class+抽象类类名{
类体(属性和方法(包含抽和非抽))
}
4、抽象类可以创建对象么?(Account act = new Account(); 抽象类无法实例化Cannot instantiate the type Account)
① 抽象类,无法创建对象,无法实例化。只能使用和多态联用,(间接创建对象)父类地址指向子类对象
②抽象类存在构造方法(只要有类都有构造方法,在类加载的时候执行),
意义在于;给儿子类构造方法第一行默认的super()调回抽象父类的构造方法)
5、抽象类的意义?(天生就当爹)
(多用于当父类被继承,然后和多态联用,不然没有意义)
PS;当然抽象类也能去继承,因为他本身也会继承Object老祖宗,只是没意义而已。
6、抽象类不能和final组合,这两个关键字是完全对立的。 一起修饰就是非法组合。
因为:final修饰的类不能被继承,但是抽象类的意义就是被继承。因此为非法组合
5、实体类(非抽类)和抽象类之间的继承形式?
前提是父类一定要有显式或者隐式的构造方法,不然子类没super去调用回父类的构造方法,报错 (间接创建对象)父类地址指向子类对象
①实体类继承抽象类(联用多态);class CreditAccount extends Account{} (面向抽象编程经常使用,和多态联用去面向抽象编程因为可以创对象子类对象) Account a = new CreditAccount();
③抽象类继承实体类(没啥意义);abstract class depositAccount extends CreditAccount{}
②抽象类继承抽象类(无线套娃) ; abstract class depositAccount extends Account{} 因为你的子类也能是别的两个类之间的共同特征,再次套娃成抽象类 (不多用,因为都无法创建两个类的对象)
④实体类继承实体类(最常用);class B extends A{} 继承提供了软件复用功能。若类B继承类A,那么建立类B时就有了A类的所有东西。
6、抽象方法?(抽象方法只能出现在抽象类)
表示:没有方法体的方法,无法实现的方法。
7、抽象方法语法结构?
修饰符列表 + abstract 返回值类型 抽象名();(注意这里是分号不是括号,无方法体)
8、抽象类和接口的抽象方法可以被继承覆盖重写么?
(可以,但是有条件)
【1】 非抽象类继承抽象类的抽象方法时,必须将抽象方法“实现”化抽象方法。通俗讲就是:方法体要写括号和代码,功能化。
因为抽象方法只能在抽象类里面,不能在非抽象的方法
【2】而如果这个继承子类也是抽象的,那么当这个抽象子类继承抽象父类时,抽象方法才可以选择覆不覆盖。如果在子类中不覆盖该抽象方法,那么必须将此方法再次声明为抽象方法。
【3】注意重写覆盖时: 必须去掉abstract重写覆盖,把分号变括号。不然无法继承并且报错。
public abstract void sum(无方法体);——》 public void sum() {有方法体}
抽象类概念和语法案例:
public class 抽象类概念和语法 {
public static void main(String[] args) {
// Account act = new Account(); 抽象类无法实例化Cannot instantiate the type Account
}
}
abstract class Account{
public Account() {
}
public abstract void sum();//抽象方法
}
//非法组合 final修饰的类不能被继承,但是抽象类的意义就是被继承。因此为非法组合
//final abstract class Account{
// }
//非抽象类继承抽象类
class CreditAccount extends Account{
public CreditAccount() {
super();//默认super调无参,或者手动打super(111);
}
public void sum() {
}
}
//抽象类继承非抽象类
abstract class DepositAccount extends CreditAccount{
}
//抽象类的子类甚至可以继续抽象,因为子类也能是别的两个类之间的共同特征,无线套娃
abstract class Num2Account extends Account{
}
总结重点:以后写程序代码代码要符合以下两个原则:
1、面向抽象(半抽)和接口(完全抽象)编程。(面向抽象父类编程,不要面向具体子类编程)
以后要多面向抽象父类和接口编程结合+使用多态,不要面向具体编程。降低耦合度,提高扩展度。
抽象类和接口可以间接创建对象,只是后边的new不能是new他们自己,但可以new他们的实现类(必须是类,不能是抽象类和接口),
人们使用抽象类和接口只是为了说明要干什么事,而让他们的实现类去根据自己的需要去实现这些方法,比如说抽象父类或者接口定义一个eat()方法,
它并没有说这个方法具体怎么做,羊就可以吃草,虎就可以吃肉,羊和虎都实现了这个吃的方法。具体行为具体分析
*
2、开闭原则(Open Close Principle)OCP ,扩展开放,对修改关闭
开闭原则是面向对象世界里最基础的设计原则,它指导我们如何建立一个稳定,灵活,可扩展的系统。开闭原则定义如下:
Software entities like classes,modules and functions should be open for extension but closed for modifications.
一个软件实体(如类,模块和函数)应该对扩展开放,对修改关闭。
3、举例;写死和不写死 :
//写死了,一个动物就必须单独写一个方法喂。
class Master{
public void feed(Cat c){}
public void feed(Dog d){}
public void feed(Bird b){}
}
//多态没有写死,ocp原则,面向抽象父类编程,不要面向具体子类编程
//一次性只要一个方法喂,扩展力强,
class Master{
public void feed(Animal a){}
//Animal a = new Bird,Animal a = new Dog,Animal a = new Cat 多态
public class 抽象类和多态连用 {
public static void main(String[] args) {
// Animal a = new Animal(); 直接报错,抽象类无法实例化创建对象
Master m = new Master("zhangsan");
Animal a = new Bird("鸟儿"); //向上转型
m.feed(a); //传动物去喂养 主人.去喂养(xxx动物对象) ,这种是人和动物直接对接,中间没有接口。
}
}
// 类;测试类,主人类,动物抽象类
class Master{
//主人类。 //总思路 ;主人(主动对象)+喂(方法)+宠物(被动对象),如果最后被动对象食物没有继续多态,那么直接就在喂方法那里直接调吃的方法就行(体现多态),不用去测试类调
String name ;
public Master() {
}
public Master(String name) {
this.name = name;
}
public void feed(Animal a) {
//主人喂养方法 传过来间接为Animal a = new Bird();这里就实现了多态
System.out.println(this.name+"在喂鸟儿");
a.eat();
}
}
abstract class Animal{
//抽象动物类
public abstract void eat();//抽象方法
}
class Bird extends Animal{
String name;
public Bird(String name) {
this.name = name;
}
// public abstract void move();//非抽象类继承了抽象类,因此抽象类的抽象方法也会继承,但是子类却是非抽象类(不能放抽象方法),因此不能放继承过来的抽象方法,直接报错
public void eat() {
//因此必须去掉abstract重写覆盖子类的抽象方法,实例化抽象方法。
System.out.println(this.name+"在吃虫子"); //可以和多态向上连用,面向抽象编程,不会固定死对象降低耦合度,提高扩展性
}
}