3【重点难点】面向对象(封装、继承、多态、初始化、static、this、抽象类、接口)
day07 匿名对象,封装,private,this,构造方法,static
day08 继承,初始化
day09 多态,抽象类,接口(极其重要)
day10 package 访问权限 内部类
day11 eclipse
以上花5天时间
成员变量和局部变量的区别(理解)
(1)在类中的位置不同
成员变量:类中方法外
局部变量:方法定义中或者方法声明上
(2)在内存中的位置不同
成员变量:在堆中
局部变量:在栈中
(3)生命周期不同
成员变量:随着对象的创建而存在,随着对象的消失而消失
局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
(4)初始化值不同
成员变量:有默认值
局部变量:没有默认值,必须定义,赋值,然后才能使用
引用类型包括:类,接口,数组
形式参数是类名的问题:如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
/*
形式参数的问题:
基本类型:形式参数的改变不影响实际参数
引用类型:形式参数的改变直接影响实际参数
*/
//形式参数是基本类型
class Demo {
public int sum(int a,int b) {
return a + b;
}
}
//形式参数是引用类型
class Student {
public void show() {
System.out.println("我爱学习");
}
}
class StudentDemo {
//如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
public void method(Student s) { //调用的时候,把main方法中的s的地址传递到了这里 Student s = new Student();
s.show();
}
}
class ArgsTest {
public static void main(String[] args) {
//形式参数是基本类型的调用
Demo d = new Demo();
int result = d.sum(10,20);
System.out.println("result:"+result);
System.out.println("--------------");
//形式参数是引用类型的调用
//需求:我要调用StudentDemo类中的method()方法
StudentDemo sd = new StudentDemo();
//创建学生对象
Student s = new Student();
sd.method(s); //把s的地址给到了这里
}
}
封装:隐藏对象的实现细节(隐藏属性),仅对外提供公共访问方式
private:可以修饰成员变量和方法,但一般只修饰成员变量。被private修饰的成员只能在本类中访问。
this:代表当前类的一个对象。场景:解决局部变量隐藏成员变量的问题(this.name = name;)
getXxx()和setXxx()方法:getXxx()是获取值的操作,只需要返回,因此是void;
setXxx()是赋值操作,需要传参,因此有明确的返回值类型,比如基本类型(int或String)。
public String getName(){
return name;
}
public void setName(String name){
this.name = name;
}
类的常用代码写法
class Phone{
private String brand;
private int price;
private String color;
public Phone(){
}
public String getBrand(){
return brand;
}
public void setBrand(String brand){
this.brand = brand;
}
public int getPrice(){
return price;
}
public void setPrice(int price){
this.price = price;
}
public String getColor(){
return color;
}
public void setColor(String color){
this.color = color;
}
}
class PhoneTest{
public static void main(String[] args){
Phone p = new Phone();
p.setBrand("苹果");
p.setPrice(6999);
p.setColor("深空灰");
System.out.println(p.getBrand()+"---"+p.getPrice()+"---"+p.getColor());
}
}
变量的范围越小越好,因为能及时被回收,释放内存。
static 静态变量属于类,也叫做类变量。静态比对象先存在。静态变量是随着类的加载而加载。
static可以通过类名调用。如jdk里有一个Math类,里面的随机数方法是:public static double random(), 可以直接调用:
double d = Math.random();
Math类没有构造方法,因为成员都是静态的。
而成员变量比如this是随着对象的创建而存在,随着对象消失而消失。
静态方法只能访问静态的成员变量和静态的成员方法。
继承:提高了代码的复用性和可维护性。让类与类之间产生关系,是多态前提(也是弊端)。
弊端体现在增加了类的耦合性。(开发原则:低耦合,高内聚。)耦合:类与类的关系;耦合:自己完成某事的能力。
还有个弊端是继承打破了封装性。
Java中继承的特点:
A:只支持单继承,不支持多继承(错误示范:extends 类1,类2)
B:支持多层继承,形成一个继承体系
继承的注意事项:
A:子类只能继承父类所有非私有成员(包括成员变量和成员方法)
B:子类不能继承父类的构造方法,但可以通过super去访问父类的构造方法。
C:不要为了部分功能而去继承。
Java继承中的成员关系
A:成员变量:子类的成员变量名称和父类中的成员变量名称一样,这个怎么访问呢
子类的方法访问变量的查找顺序:
在子类方法的局部范围找,有就使用。
在子类的成员范围找,有就使用。
在父类的成员范围找,有就使用。
找不到,就报错。(注意:并不会去父类的方法局部范围找!!
B:构造方法
a:子类的构造方法默认会去访问父类的无参构造方法(是为了子类访问父类数据的初始化)
b:父类中如果没有无参构造方法,怎么办?
子类的构造方法默认会去访问父类的无参构造方法。
如果父类中没有无参构造方法,子类可以通过super去明确调用带参构造方法。
C:成员方法:子类的成员方法和父类中的成员方法名称一样,这个怎么访问呢
通过子类对象访问一个方法的查找顺序:
在子类中找,有就使用
在父类中找,有就使用
找不到,就报错
静态代码块,构造代码块,构造方法的顺序问题?
静态代码块 > 构造代码块 > 构造方法
静态代码块(Fu)>静态代码块(Zi)>构造代码块(Fu)>构造方法(Fu)>构造代码块(Zi)>构造方法(Zi)
子类重写父类方法时,权限最好一致(是public就都是public)
final可以修饰类,方法和变量:final修饰的类不能被继承。final修饰的方法不能被重写。final修饰的变量不能被重新赋值(变成一个自定义常量,和常量一样,只能被赋值一次)。
多态:某一个事物在不同时刻表现出来的不同状态
A:具体类多态(几乎没有);B:抽象类多态(常用);C:接口多态(最常用)
多态的前提:A:要有继承关系;B:要有方法重写;C:要有父类引用指向子类对象。(父 f = new 子();)
多态中的成员访问特点
A:成员变量
编译看左边,运行看左边
B:构造方法
子类的构造都会默认访问父类构造
C:成员方法
编译看左边,运行看右边(成员方法有重写)
D:静态方法
编译看左边,运行看左边
多态的好处:A:提高代码的维护性(继承体现);B:提高代码的扩展性(多态体现)
多态的弊端:父不能使用子的特有功能。现象:子可以当作父使用,父不能当作子使用。
对象间的转型问题:
A:向上转型: Fu f = new Zi();
B:向下转型:Zi z = (Zi)f; //要求该f必须是能转换为Zi的!(也就是必须在多态的前提下才能转,此时f本身就是Zi)
class 孔子爹 {
public int age = 40;
public void teach() {
System.out.println("讲解JavaSE");
}
}
class 孔子 extends 孔子爹 {
public int age = 20;
public void teach() {
System.out.println("讲解论语");
}
public void playGame() {
System.out.println("英雄联盟");
}
}
//Java培训特别火,很多人来请孔子爹去讲课,这一天孔子爹被请走了
//但是还有人来请,就剩孔子在家,价格还挺高。孔子一想,我是不是可以考虑去呢?
//然后就穿上爹的衣服,带上爹的眼镜,粘上爹的胡子。就开始装爹
//向上转型
孔子爹 k爹 = new 孔子();
//到人家那里去了
System.out.println(k爹.age); //40
k爹.teach(); //讲解论语
//k爹.playGame(); //这是儿子才能做的,所以k爹会报错!
//讲完了,下班回家了
//脱下爹的装备,换上自己的装备
//向下转型
孔子 k = (孔子) k爹;
System.out.println(k.age); //20
k.teach(); //讲解论语
k.playGame(); //英雄联盟
/*
不同地方饮食文化不同的案例
*/
class Person {
public void eat() {
System.out.println("吃饭");
}
}
class SouthPerson extends Person {
public void eat() {
System.out.println("炒菜,吃米饭");
}
public void jingShang() {
System.out.println("经商");
}
}
class NorthPerson extends Person {
public void eat() {
System.out.println("炖菜,吃馒头");
}
public void yanJiu() {
System.out.println("研究");
}
}
class DuoTaiTest2 {
public static void main(String[] args) {
//测试
//南方人
Person p = new SouthPerson();
p.eat();
System.out.println("-------------");
SouthPerson sp = (SouthPerson)p;
sp.eat();
sp.jingShang();
System.out.println("-------------");
//北方人
p = new NorthPerson();
p.eat();
System.out.println("-------------");
NorthPerson np = (NorthPerson)p;
np.eat();
np.yanJiu();
}
}
/*
炒菜,吃米饭
-------------
炒菜,吃米饭
经商
-------------
炖菜,吃馒头
-------------
炖菜,吃馒头
研究
*/
开发中一般是利用多态声明形式参数,并将创建子类的匿名对象作为实际参数。
抽象类中不一定有抽象方法,但是有抽象方法的类一定是抽象类。抽象类不能实例化。
抽象类的子类
a:是一个抽象类。
b:是一个具体类。这个类必须重写抽象类中的所有抽象方法。
抽象方法构造:public abstract void teach();注意这里没有{},因为抽象方法没有方法体!!
abstract不能和哪些关键字共存
a:final 冲突
b:private 冲突
c:static 无意义
抽象类总结规定
1. 抽象类不能被实例化(初学者很容易犯的错),如果被实例化,就会报错,编译无法通过。只有抽象类的非抽象子类可以创建对象。
2. 抽象类中不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
3. 抽象类中的抽象方法只是声明,不包含方法体,就是不给出方法的具体实现也就是方法的具体功能。
4. 构造方法,类方法(用static修饰的方法)不能声明为抽象方法。
5. 抽象类的子类必须给出抽象类中的抽象方法的具体实现,除非该子类也是抽象类。
接口不能实例化。只能按照多态的方式来实例化。(最常用)
接口类: interface 接口名{} 没有class!!!因为只是功能扩展。
类实现接口: class 类名 implements 接口名{}
class InterImpl implements Inter{}
接口的实现类
a:是一个抽象类。【意义不大】
b:是一个具体类,这个类必须重写接口中的所有抽象方法。【推荐】
接口的成员特点:
A:成员变量
只能是常量
默认修饰符:public static final
B:构造方法
没有构造方法
C:成员方法
只能是抽象方法
默认修饰符:public abstract
抽象类和接口的区别
A:成员区别
抽象类:
成员变量:可以变量也可以常量
构造方法:有
成员方法:可以抽象也可以非抽象
接口:
成员变量:只可以常量
成员方法:只可以是抽象
B:关系区别:
类与类:继承,单继承
类与接口:实现,单实现,多实现
接口与接口:继承,单继承,多继承
C:设计理念不同【非常重要】
抽象类:is a,抽象类中定义的是该继承体系的共性功能。
接口:like a,接口中定义的是该继承体系的扩展功能。(类似于USB扩展接口)
形式参数和返回值的问题(理解)
(1)形式参数:
类名:需要该类的对象
抽象类名:需要该类的子类对象
接口名:需要该接口的实现类对象
(2)返回值类型:
类名:返回的是该类的对象
抽象类名:返回的是该类的子类对象
接口名:返回的是该接口的实现类的对象
包:package 包名;
带包的编译和运行:(自动式) javac -d . HelloWorld.java
导包:import 包名...类名;
package,import,class的顺序:package > import > class
权限修饰符
本类 同一个包下 不同包下的子类 不同包下的无关类 private Y 默认 Y Y protected Y Y Y public Y Y Y Y
这四种权限修饰符在任意时刻只能出现一种。 public class Demo {}
匿名内部类的本质:其实是继承该类或者实现接口的子类的匿名对象
格式:
new 类名或者接口名() {
重写方法;
}
Object类要掌握的方法
A:toString()
返回对象的字符串表示,默认是由类的全路径+'@'+哈希值的十六进制表示。
这个表示其实是没有意义的,一般子类都会重写该方法(把该类所有成员变量值返回即可)。最终还是自动生成。
B:equals()
比较两个对象是否相同。默认情况下,比较的是地址值是否相同。
而比较地址值是没有意义的,所以,一般子类也会重写该方法。最终还是自动生成。
==和equals()的区别?
A:==
基本类型:比较的是值是否相同
引用类型:比较的是地址值是否相同
B:equals()
只能比较引用类型。默认情况下,比较的是地址值是否相同。
但是,我们可以根据自己的需要重写该方法(一般都是用来比较对象的成员变量值是否相同)。