面向对象第三天:
回顾:
-
构造方法:构造函数、构造器、构建器--------复用给成员变量赋值
- 作用:给成员变量赋初值
- 与类同名,没有返回值类型(连void)
- 创建对象时被自动调用
- 若自己不写构造,默认一个无参构造,若自己写了构造,则不再默认提供
- 可以重载
-
this:指代当前对象,哪个对象调用方法它指的就是哪个对象
this的用法:
this.成员变量名-------------------------访问成员变量
当成员变量与局部变量同名时,若想访问成员变量则this不能省略
-
null:表示空,没有指向任何对象
若引用的值为null,则该引用不能进行任何操作了,若操作则发生 NullPointerException空指针异常
-
引用类型数组:
Bomb[] bs = new Bomb[3]; bs[0] = new Bomb(100,200); //1)new bs[1] = new Bomb(200,300); bs[2] = new Bomb(300,400); System.out.println(bs[0].width); //2)访问属性需打点
笔记:
1.引用类型数组:
与基本类型数组的区别:
给数组的元素赋值必须new一个对象
若想访问对象数据必须通过数组元素打点
package oopday9.day03.StudentReference;
/**
* 基本数据类型(basic data type)默认值为————————0!
* //声明整形数组arr,包含3个元素,每个元素都是int类型,默认值为0
* int[] arr = new int[3];//基本数据类型
* arr[0] = 100;
*
*
* 引用数据类型(reference data type)数组的演示:————————默认值为null!
* //声明Student类型数组s,包含3个元素,每个元素都是Student型,默认值为null
* //Student是自己写的,就是引用数据类型:
* Student[] stus = new Student[3];//创建Student数组对象
*
*/
public class Student {
String name;
int age;
String address;
Student(String name, int age, String address){
this.name = name;
this.age = age;
this.address = address;
}
void sayHi(){
System.out.println("大家好,我叫"+name+",今年"+age+"岁了,家住"+address);
}
public static void main(String[] args) {
int[] arr = new int[3];//基本数据类型
arr[0] = 100;
System.out.println(arr[0]);
/* 声明Student引用类型数组s,包含3个元素,每个元素都是Student型,默认值为null
Student是自己写的,就是引用数据类型: */
//1.创建Student数组对象
Student[] stus = new Student[3];
System.out.println(stus);//【@28d93b30】----------变量存着是地址!!!
/*
Student stus1 = new Student("张三",25,"河北");
stus[0] = stus1;
上两句同下:
*/
//2.创建Student对象(即给变量传参赋值的时候)-------注1:只要是引用类型,就得new一个构造方法来传参:Student();
stus[0] = new Student("张三",25,"河北");
stus[1] = new Student("李四",26,"佳木斯");
stus[2] = new Student("王五",27,"山东");
//注1:【引用类型直接访问数组的元素输出的是地址!】
System.out.println(stus[0]);//@28d93b30----------数组的元素存着是地址!!!
//(1)输出第一个学生的名字----------------------注2:【引用类型想访问数组的元素需要通过数组元素打点】
System.out.println(stus[0].name);//张三
//(2)修改第2个学生的年龄为24------------------注3:【若想访问具体元素的特有属性(name/age...)先取到想访问的元素,再去打点】
stus[1].age = 24;
//(3)第3个学生跟大家问好
stus[2].sayHi();
//(4)遍历所有学生
for(int i=0;i<stus.length;i++){
System.out.println(stus[i].name);//①输出每个学生的名字
stus[i].sayHi();//②跟所有学生问好
}
//内存过程:
//1.创建了一个Student数组对象:
// 【变量】保存在【栈中】并且【有自己的地址】-------------------------指向堆中的Student数组对象;
// 【Student数组对象保存在堆中】,在堆中就有了Student数组对象,【包含数组的所有元素(stus[0]/stus[1]...)】,引用数据类型默认值为null
//2.创建两个Student对象的同时在堆中又产生了两个,因为是引用类型,
// 所以在堆中元素保存的是地址【@28d93b30,即内存图中的0x2222】-------指向了Student对象
//3.当修改第2个学生的age为24时,又因为数组是连续的,基于地址就找到了Student对象(保存着是属性name/age...)中的三个参数!
}
}
2. 继承:
-
作用:代码复用
-
通过extends来实现继承
-
超类/父类:共有的属性和行为
派生类/子类:特有的属性和行为
-
派生类既能访问自己的,也能访问超类的,但超类不能访问派生类的
-
一个超类可以有多个派生类
一个派生类只能有一个超类-----------单一继承
-
具有传递性
-
java规定:构造派生类之前必须先构造超类
- 派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
- 派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
super()调用超类构造方法,必须位于派生类构造方法的第一行
package oopday9.day03.extends1;
/**
* 继承:------------------extends关键字
*
* 继承格式:
* class 父类 {
* }
*
* class 子类 extends 父类 {
* }
*
* 继承特点:
* (1)作用:代码复用
* (2)通过extends来实现继承
* (3)超类/父类:共有的属性和行为
* (4)派生类/子类:特有的属性和行为
* (5)派生类既能访问自己的,也能访问超类的,但超类不能访问派生类的
* (6)一个超类可以有多个派生类;一个派生类只能有一个超类-----------单一继承
* (7)具有传递性
* (8)java规定:构造派生类之前必须先构造超类
*
*/
public class Person {//--------可以访问a------(6)一个超类可以有多个派生类;一个派生类只能有一个超类
int a = 5;
int b = 6;
Person(){
System.out.println("我是超类构造");
}
void eat(){ }
public static void main(String[] args) {
Father f = new Father();
f.eat();
}
}
class Father extends Person{//-可以访问b+a
int b;
Father() { }
void eat(){//------方法的重写
this.a = 6;//因为继承了超类,this默认超类的
super.b = 7;//访问超类的成员变量
}
}
class Boy extends Father{//---可以访问b+a+c---(7)具有传递性
int c;
void eat(String name){//-----派生类自己的方法
}
}
3. super:指代当前对象的超类对象
super的用法:
- super.成员变量名----------------------访问超类的成员变量(了解)
- super.方法名()---------------------------调用超类的方法----------明天讲
- super()-------------------------------------调用超类的构造方法
package oopday9.day03;
/**
*《 super的演示》:
* super----------指代当前对象的超类对象
* super的用法:
* (1)super.成员变量名----------------------访问超类的成员变量(了解)
* (2)super.方法名()------------------------调用超类的方法
* (3)super()------------------------------调用超类的构造方法
*
* java规定:构造派生类之前必须先构造超类:
* -派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
* -派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
* -super()调用超类构造方法,必须位于派生类构造方法的第一行
*
*
* 例:下面程序中,为什么会先输出【超类构造方法】,再输出【派生类构造方法】?
* 原因:在main中,new了一个Boo对象,所以先调用Boo的无参构造,在Boo无参构造中:
* 若不写super有参构造,则在Boo的无参构造里第一行默认有【super();】无参构造,
* 此时会调用超类Aoo的无参构造先输出:【超类构造方法】,再输出:【派生类构造方法】
*/
public class SuperDemo {
int c = 5;
SuperDemo(int a){
}
public static void main(String[] args) {
Boo o = new Boo();
int a = 9;
int b = 10;
}
}
class Aoo extends SuperDemo{
Aoo(){
/* ↓↓↓↓↓↓↓重要重要重要重要重要重要重要重要↓↓↓↓↓↓↓↓ */
/** 若超类中为有参构造【 SuperDemo(int a){ } 】,
则在派生类的构造中必须写:【super(3);】有参构造,且位于第一行!
否则会报错,但不会影响Boo报错,因为Boo默认调用的Aoo的无参构造---Boo是间接继承了SuperDemo,! */
super(3);//----------------------1.必须位于第一行!!
super.c = 15;//super.成员变量名------2.访问超类的成员变量
System.out.println("我是超类构造方法");
}
void show(){
System.out.println("我是超类自己写的方法");
}
}
class Boo extends Aoo{
Boo(){
//--------自己不写系统会默认加的!!!!!
super();//即使没有这句话,但------------系统也默认用:【super();】调用的超类的无参构造方法!!
super.show();//super.方法名()---------3.调用超类的方法
System.out.println("我是派生类构造方法");
//super();//编译错误,-----super()-----4.调用超类构造方法,必须位于派生类构造方法的第一行!!
}
}
精华笔记:
1、引用类型数组:
与基本类型数组的区别:
给数组元素赋值必须new一下
若想访问对象数据必须通过数组元素打点
2、继承:
-
作用:代码复用
-
通过extends来实现继承
-
超类/父类:共有的属性和行为
派生类/子类:特有的属性和行为
-
派生类既能访问自己的,也能访问超类的,但超类不能访问派生类的
-
一个超类可以有多个派生类
一个派生类只能有一个超类-----------单一继承
-
具有传递性
-
java规定:构造派生类之前必须先构造超类
- 派生类的构造方法中若没有调用超类的构造方法,则默认super()调用超类的无参构造方法
- 派生类的构造方法中若自己调用了超类的构造方法,则不再默认提供
super()调用超类构造方法,必须位于派生类构造方法的第一行
3、super:指代当前对象的超类对象
super的用法:
- super.成员变量名----------------------访问超类的成员变量(了解)
- super.方法名()---------------------------调用超类的方法----------明天讲
- super()-------------------------------------调用超类的构造方法
补充:
1.引用类型数组:
与基本类型数组的区别:
- 给数组元素赋值必须new一下
- 若想访问对象数据必须通过数组元素打点
2.继承意味着代码虽然我没有写,但也属于我,只是没有写在一起而已
3. 泛化:将共有的抽出来的过程,泛化是设计层面的概念,从代码实现层面来说咱们就是继承,泛化就是继承
4. 继承要符合is a(是一个)的关系
回顾:
1、引用类型数组:
- 给元素赋值new一下
- 访问数据需通过数组元素打点
Student[] s = new Student();
s[0] = new Student("张三",25,"河北");
System.out.println(s[0].move);
2、继承:
- 代码复用,
- 通过extends继承
- 超类:共有的 ; ;派生类:特有的
- 派生类可以访问派生类自己的+超类的,超类只能访问超类自己的
- 单一继承
- 传递性
java规定:构造派生类之前必须先构造超类
- 1.派生类构造中若自己不调超类构造,则默认super()调超类无参构造
- 2.派生类构造中若自己调用了超类构造,则不再默认提供
-----super()调用构造方法必须位于派生类构造方法的第一行
3、super:指代当前对象的超类对象
super用法:
- super.成员变量名---------------------------访问超类的成员变量
- super.方法名()-------------------------------调用超类的方法--------一会讲
- super()-----------------------------------------调用超类的构造方法
面向对象第四天:
笔记:
1、向上造型:前提是继承
- 超类型的引用(变量)指向了派生类的对象------------------------例:Animal o = new Tiger();
- 引用能"点" 出来什么,看引用(o:即变量)本身的类型----------例:【o.Animal类中的东西】
1.何时向上造型???
---当多重角色能干的事是一样的,可以将多种角色造型到超类型数组中,统一访问。
2.向上造型的意义:--------实现代码复用
当多种角色能干的事是一样的,可以将那多种角色造型到超类数组中,统一访问
package oopday9.day04.upload;
public class Aoo {
int a;
void show(){
}
Aoo(){
System.out.println("我是超类");
}
}
package oopday9.day04.upload;
public class Boo extends Aoo{//还默认包含Aoo的a和show()
int b;
void test(){
}
Boo(){
System.out.println("我是派生类");
}
}
package oopday9.day04.upload;
//向上造型的演示
public class UploadDemo {
public static void main(String[] args) {
Aoo o1 = new Aoo();
o1.a = 1;
o1.show();
// o1.b; //---------编译错误,超类的引用不能【点】出派生类的,能点出来什么,看引用的类型
// o1.test();
Boo o2 = new Boo();
o1.a = 1;//---------正确。派生类的引用可以【点】出超类的
o1.show();
o2.b = 2;
o2.test();
Aoo o3 = new Boo();//!向上造型 一个超类型的引用(o3)指向了派生类
o3.a = 3;
o3.show();
// o3.b = 4; //------编译错误 超类的引用(o3)不能点出派生类的,能点出来什么,看引用的类型
// o3.test();//编译错误,能点出来什么,看引用的类型
}
}
2、方法的重写(override/overriding):重新写、覆盖
- 发生在父子类中,方法名相同,参数列表相同
- 重写方法被调用时,看对象的类型()------------这是规定,记住就OK
当派生类觉得超类的行为不够好时,可以重写
package oopday9.day04.override;
import oopday9.day04.Person;
import oopday9.day04.Student;
/**
* 《方法的重写(override/overriding)》
* 1、概念:重新写(当派生类觉得超类的行为不够好时,可以重写)
*
* 2、规定:
* -(1)发生在父子类中,方法名相同,参数列表相同
* -(2)重写方法被调用时,看对象的类型()
*
* 3、规则:两同 两小 一大
* 两同: 方法名与参数列表 和 父类方法保持一致
* 两小:
* 子类方法的返回值类型 <= 父类方法的返回值类型。
* 子类方法抛出的异常类型 <= 父类方法抛出的异常类型
* 注意1:这里的<=说的是继承关系,不是值的大小
* 注意2:如果父类方法的返回值类型是void,子类保持一致即可
* 注意3:子类不可以重写父类的私有方法,还是因为不可见
* 一大: 子类方法的修饰符权限 >= 父类方法的修饰符权限
*
* 4、意义:是在不修改源码的前提下,进行功能的修改和拓展(OCP原则:面向修改关闭,面向拓展开放)
*
*/
public class Restaurant {
void show(){
System.out.println("做中餐");
}
double test(){ return 0.0; }
Student say(){ return null; }
public static void main(String[] args) {
Aoo o = new Aoo();
//---------2、(2)重写方法被调用时,看【引用(o:即变量)new出来】对象的类型(Aoo)
//【超类中的doing()方法,只是为了能点出来。若超类和派生类都有该方法,则调用派生类的;若派生类中没有则调超类的】
o.doing("0"); //调用的是------>Boo的doing()
Boo o2 = new Boo();
o2.doing("1");//调用的是------>Boo的doing()
}
}
class Aoo extends Restaurant{
//(1)还是想做中餐,不需要重写
void show(){//(2)我想改做西餐----------------需要重写(只写西餐)
System.out.println("做西餐");
}
// void show(){//(3)想在中餐基础上+西餐--------需要重写(先super中餐,再加入西餐)
// super.doing();
// System.out.println("做西餐");
// }
//int show(){ return 5; } //编译错误,子类方法的返回值类型 <= 父类方法的返回值类型。
//int test(){ return 0; } //编译错误,基本数据类型此时不符合大小原则,必须为double
//Person say(){ return null; } //编译错误,在派生类中重写方法为引用类型时必须:<= 派生类
void doing(String r){
System.out.println("我是Aoo中自己写的方法");
}
}
class Boo extends Aoo{
void doing(String r){
System.out.println("我是Boo中重写Aoo的方法");
}
}
3、重写与重载的区别:重点(常见的面试题)
-
重写:发生在父子类中,方法名相同,参数列表相同
一般用于在派生类中修改超类的方法
-
重载:发生在同一类中,方法名相同,参数列表不同
是完全不同的方法,只是方法名相同而已
重写与重载的区别:重点(常见的面试题)
&&重写:发生在父子类中,方法名相同,参数列表相同;一般用于在派生类中修改超类的方法
规定:重写方法被调用时,看对象的类型(例:超类是void do(){} 当超类中重写方法被调用时,派生类中必须写成和超类一样:super.do();)
原则:两同,两小,一大
两同:签名(方法名和参数)相同
两小:①派生类方法的返回值类型必须 <= 超类方法;②派生类方法抛出的异常必须<=超类方法;
一大:派生类的访问权限必须>=超类方法
&&重载:发生在同一类中,方法名相同,参数列表不同;是完全不同的方法,只是方法名相同而已,对于返回值类型并没有要求。
1、变量:------成员变量(实例变量和静态变量) 和 局部变量
可以改变的数,称为变量。在Java语言中,所有的变量在使用前必须声明。
一般通过“变量类型 变量名 = 变量值 ;”这三部分来描述一个变量。如:int a = 3 ;
变量的使用原则:就近原则,即尽量控制变量的使用范围到最小
(1)变量的默认值测试:
创建包: cn.tedu.basic
创建类: TestVariable1.java
package cn.tedu.design;
/*本类用于测试各种类型变量的默认值*/
public class TestVariable1 {
static String name;
static byte b;//整数类型默认值都是0
static short c;
static int d;
static long e;
static float f;//小数类型的默认值是0.0
static double g;
static char j;//char类型的默认值是\u0000
static boolean h;//boolean类型的默认值是false
public static void main(String[] args) {
System.out.println(name);//null,引用类型的默认值
System.out.println(b);
System.out.println(c);
System.out.println(d);
System.out.println(e);
System.out.println(f);
System.out.println(g);
System.out.println(h);
System.out.println(j);
System.out.println(h);
}
}
2、成员变量(实例变量和静态变量)--------写在类中,方法外(有默认值)
位置:定义在类里方法外
注意:不用初始化,也会自动被初始化成默认值
生命周期:整个类中,类消失了,成员变量才会释放
分为:
1(1)实例变量:①无static修饰属于对象②存储在堆中③有几个对象就有几份④通过引用打点来访问
-⑤例:类中有一个变量:int num
(2)静态变量:①由static修饰属于类 ②存储在方法区中③只有一份④常常通过类名点来访问
3、局部变量--------方法中(没有默认值)
位置:定义在方法里或者方法的声明上
注意:必须手动初始化来分配内存.如:int i = 5;或者int i; i = 5;
生命周期:随着方法的调用而存在,方法运行完毕就释放了
4、成员变量 与 局部变量区别:
成员变量:
写在类中,方法外的。可以在整个类中访问。有默认值。
局部变量:
写在方法中的(包括方法的参数)。只能在当前方法中访问。没有默认值。
【注:方法中的局部变量没有默认值,作为参数的局部变量有默认值。】
(1)局部变量与成员变量测试:
1.
package oopday9.day04.CyJb;
import java.util.Arrays;
/**
* 成员变量:写在类中,方法外的。可以在整个类中访问。有默认值。
* 局部变量:写在方法中的(包括方法的参数)。只能在当前方法中访问。没有默认值。
* 【注:方法中的局部变量没有默认值,作为参数的局部变量有默认值。】
*/
public class Doo {
int a;//--------------------成员变量(整个类中访问),有默认值
public static void main(String[] args) {
int d;
System.out.println(Arrays.toString(args));
//System.out.println(d);//编译报错
Eoo o = new Eoo();
o.show(2);
}
}
class Eoo extends Doo{
/**
* 为什么局部变量c没有默认值,而作为方法的参数的局部变量b却有?
* 答:
* 局部变量b也没有默认值,但是当new一个对象时会传参(见上面main中的new对象↑),
* 就自然给局部变量b赋值初始化了【o.show(b: 2);】,所以在方法里打印b的值时不会编译报错。
*
*/
void show(int b){//----------局部变量b(当前方法中访问)和main方法里的局部变量类似,详情见该包的图片
int c;//-----------------局部变量c(当前方法中访问):只声明了没有初始化,没有默认值
System.out.println(a);
System.out.println(b);
//System.out.println(c);//编译报错
}
}
2.
创建包: cn.tedu.basic
创建类: TestVariable2.java
package cn.tedu.oop;
/**本类用于测试变量的使用*/
public class TestVariable2 {
//2.定义成员变量:
//1)位置:类里方法外
//2)无需手动初始化,会自动赋予对应类型的默认值
//3)作用域:在整个类中生效,类消失,变量才会消失
static int count;
//3.变量有一个使用的原则:就近原则
static int sum = 200;
public static void main(String[] args) {
//1.定义局部变量:
//1)位置:在方法里/局部代码块里
//2)必须手动初始化
//3)作用域:在方法/局部代码块中,对应的代码执行完局部变量就被释放
int sum = 100;//定义在方法中的局部变量sum
System.out.println(sum);//变量的就近原则:使用的都是自己附近的变量,100
System.out.println(count);
for (int i = 0; i < 10; i++) {//局部变量i只能在循环中使用
System.out.println(i);
}
//System.out.println(i);//报错:无法引用变量i:i cannot be resolved to a variable
}
}
精华笔记
1、向上造型:前提是继承
- 超类型的引用(变量)指向了派生类的对象------------------------例:Animal o = new Tiger();
- 引用能"点" 出来什么,看引用(o:即变量)本身的类型----------例:【o.Animal类中的东西】
2、方法的重写(override/overriding):重新写、覆盖
- 发生在父子类中,方法名相同,参数列表相同
- 重写方法被调用时,看对象的类型------------这是规定,记住就OK
当派生类觉得超类的行为不够好时,可以重写
3、重写与重载的区别:-----------常见面试题
重写(override):发生在父子类中,方法名相同,参数列表相同
重载(overload):发生在同一类中,方法名相同,参数列表不同
补充:
1.向上造型的意义:--------实现代码复用
当多种角色能干的事是一样的,可以将那多种角色造型到超类数组中,统一访问