面向对象"/>
Java基础(五)面向对象
1.面向对象特征* 封装(encapsulation) 是指隐藏对象的属性和实现细节,仅对外提供公共访问方式。
* 隐藏实现细节,提供公共的访问方式
* 提高了代码的复用性
* 提高安全性。
* A:继承的好处
* a:提高了代码的复用性
* b:提高了代码的维护性
* c:让类与类之间产生了关系,是多态的前提
* B:继承的弊端
* 类的耦合性增强了。
* 开发的原则:高内聚,低耦合。
* 耦合:类与类的关系
* 内聚:就是自己完成某件事情的能力
* 多态(polymorphism) 事物存在的多种形态
* 前提:要有继承关系;要有方法重写;要有父类引用指向子类对象
* 多态的好处:提高了代码的维护性;提高了代码的扩展性
* 多态的弊端:不能使用子类的特有属性和行为
2.成员变量和局部变量的区别
* A:在类中的位置不同
* 成员变量:在类中方法外
* 局部变量:在方法定义中或者方法声明上
* B:在内存中的位置不同
* 成员变量:在堆内存(成员变量属于对象,对象进堆内存)
* 局部变量:在栈内存(局部变量属于方法,方法进栈内存)
* C:生命周期不同
* 成员变量:随着对象的创建而存在,随着对象的消失而消失
* 局部变量:随着方法的调用而存在,随着方法的调用完毕而消失
* D:初始化值不同
* 成员变量:有默认初始化值
* 局部变量:没有默认初始化值,必须定义,赋值,然后才能使用。
* 注意事项:
* 局部变量名称可以和成员变量名称一样,在方法中使用的时候,采用的是就近原则。
* 基本数据类型变量包括哪些:byte,short,int,long,float,double,boolean,char
* 引用数据类型变量包括哪些:数组,类,接口,枚举
3.方法的形式参数是类名的时候如何调用
A:方法的参数是类名public void print(Student s){}//print(new Student());
* 如果你看到了一个方法的形式参数是一个类类型(引用类型),这里其实需要的是该类的对象。
引用数据类型当形式参数的时候,是给一个地址值
基本数据类型当形式参数的时候,是给一个值
public class Test {public static void main(String[] args) {print(10);Student st = new Student(); //创建对象,并将对象的地址值赋值给sprint(st);}public static void print(int x){ //基本数据类型当做形式参数System.out.println(x);}public static void print(Student s){ //引用数据类型当做形式参数s.name = "张三";s.age = 23;s.speak();}}
class Student{String name;int age;public void speak(){System.out.println(name+"..."+age);}
}
4.匿名对象
*匿名对象只适合对方法的一次调用,因为调用多次就会产生多个对象
*匿名对象可以调用属性并赋值,但是没有意义,因为调用完后变成垃圾
根据内存图可以看出并不会输出所赋的值
* A:什么是匿名对象
* 没有名字的对象
* B:匿名对象应用场景
* a:调用方法,仅仅只调用一次的时候。
* 那么,这种匿名调用有什么好处吗?
* 节省代码
* 注意:调用多次的时候,不适合。匿名对象调用完毕就是垃圾。可以被垃圾回收器回收。
* b:匿名对象可以作为实际参数传递
public class Test {public static void main(String[] args) { method(new Student()); }public static void method(Student ss){ss.age = 18;ss.name = "wo";ss.speak();}
}
class Student{String name;int age;public void speak(){System.out.println(name+"..."+age);}
}
5.this关键字
* 代表当前对象的引用
* 用来区分成员变量和局部变量重名 set get 方法中
6.构造方法
(1)概述和格式
* A:构造方法概述和作用
* 给对象的数据(属性)进行初始化
* B:构造方法格式特点
* a:方法名与类名相同(大小也要与类名一致)
* b:没有返回值类型,连void都没有
* c:没有具体的返回值return;
(2)注意事项
* a:如果我们没有给出构造方法,系统将自动提供一个无参构造方法。
* b:如果我们给出了构造方法,系统将不再提供默认的无参构造方法。
* 注意:这个时候,如果我们还想使用无参构造方法,就必须自己给出。建议永远自己给出无参构造方法
7.static关键字
含有static关键字的内存分配图 : 在方法区里加载类的时候,会分为两个区:静态区和非静态区
A:static关键字的特点
* a:随着类的加载而加载
* b:优先于对象存在
* c:被类的所有对象共享
* 共性用静态,特性用非静态
* d:可以通过类名调用 非静态则不可以
* 其实它本身也可以通过对象名调用。
* 推荐使用类名调用。 (减少对象的创建,节省空间)
* 静态修饰的内容一般我们称其为:与类相关的,类成员
* B:static的注意事项
* a:在静态方法中是没有this关键字的
* 如何理解呢?
* 静态是随着类的加载而加载,this是随着对象的创建而存在。
* 静态比对象先存在。
* b:静态方法只能访问静态的成员变量和静态的成员方法
* 静态方法:
* 成员变量:只能访问静态变量
* 成员方法:只能访问静态成员方法
* 非静态方法:
* 成员变量:可以是静态的,也可以是非静态的
* 成员方法:可是是静态的成员方法,也可以是非静态的成员方法。
* 简单记:
* 静态只能访问静态。
用自己的话说:静态是最先加载的,而对象之后才创建的,静态优先存在,因为静态先存在,而非静态的还没有存在,故静态的不能访问非静态的。
静态变量和成员变量的区别
* 静态变量也叫类变量 成员变量也叫对象变量
* A:所属不同
* 静态变量属于类,所以也称为为类变量
* 成员变量属于对象,所以也称为实例变量(对象变量)
* B:内存中位置不同
* 静态变量存储于方法区的静态区
* 成员变量存储于堆内存
* C:内存出现时间不同
* 静态变量随着类的加载而加载,随着类的消失而消失
* 成员变量随着对象的创建而存在,随着对象的消失而消失
* D:调用不同
* 静态变量可以通过类名调用,也可以通过对象调用
* 成员变量只能通过对象名调用
8.代码块
* A:代码块概述
* 在Java中,使用{}括起来的代码被称为代码块。
* B:代码块分类
* 根据其位置和声明的不同,可以分为局部代码块,构造代码块,静态代码块,同步代码块(多线程)。
* C:常见代码块的应用
* a:局部代码块
* 在方法中出现;限定变量生命周期,及早释放,提高内存利用率
* b:构造代码块 (初始化块)
* 在类中方法外出现;多个构造方法方法中相同的代码存放到一起,每次调用构造都执行,并且在构造方法前执行
每创建一次对象都会先执行构造代码块,优先于构造方法执行
* c:静态代码块
* 在类中方法外出现,并加上static修饰;用于给类进行初始化,在加载的时候就执行,并且只执行一次。
* 一般用于加载驱动
class Student {static {System.out.println("Student 静态代码块");}{System.out.println("Student 构造代码块");}public Student() {System.out.println("Student 构造方法");}}class Demo2_Student {static {System.out.println("Demo2_Student静态代码块");}public static void main(String[] args) {System.out.println("我是main方法");Student s1 = new Student();Student s2 = new Student();}}
输出:
Demo2_Student静态代码块
我是main方法
Student 静态代码块
Student 构造代码块
Student 构造方法
Student 构造代码块
Student 构造方法
9.继承
(1)this和super的区别和应用
* A:this和super都代表什么
* this:代表当前对象的引用,谁来调用我,我就代表谁
* super:代表当前对象父类的引用
* B:this和super的使用区别
* a:调用成员变量
* this.成员变量 调用本类的成员变量,也可以调用父类的成员变量
* super.成员变量 调用父类的成员变量
* b:调用构造方法
* this(...) 调用本类的构造方法
* super(...) 调用父类的构造方法
* c:调用成员方法
* this.成员方法 调用本类的成员方法,也可以调用父类的方法
* super.成员方法 调用父类的成员方法
(2)构造方法
* A:子类中所有的构造方法默认都会访问父类中空参数的构造方法
* B:原因
* 因为子类会继承父类中的数据,可能还会使用父类的数据。
* 所以,子类初始化之前,一定要先完成父类数据的初始化。
* 其实:
* 每一个构造方法的第一条语句默认都是:super() Object类最顶层的父类。
class Father {public Father() {super(); //每个类默认继承object类 extands Object System.out.println("Father 的构造方法");}
}class Son extends Father {public Son() {super(); //这是一条语句,如果不写,系统会默认加上,用来访问父类中的空参构造System.out.println("Son 的构造方法");}
}
* 父类没有无参构造方法,子类怎么办? super、this解决
对this、super的调用必须是构造器的第一个语句。
看程序写结果
class Fu{public int num = 10;public Fu(){System.out.println("fu");}}class Zi extends Fu{public int num = 20;public Zi(){System.out.println("zi");}public void show(){int num = 30;System.out.println(num);System.out.println(this.num);System.out.println(super.num);}}class Test1_Extends {public static void main(String[] args) {Zi z = new Zi();z.show();}}
输出:
Fu
zi
30
20
10
这个程序题经常会考
class Fu {static {System.out.println("静态代码块Fu");}{System.out.println("构造代码块Fu");}public Fu() {System.out.println("构造方法Fu");}
}class Zi extends Fu {static {System.out.println("静态代码块Zi");}{System.out.println("构造代码块Zi");}public Zi() {System.out.println("构造方法Zi");}
}
class Test1_Extends {public static void main(String[] args) {Zi z = new Zi();}
}
输出:
静态代码块Fu
静态代码块Zi
构造代码块Fu
构造方法Fu
构造代码块Zi
构造方法Zi
10.方法重写
* A:方法重写注意事项
* a:父类中私有方法不能被重写
* 因为父类私有方法子类根本就无法继承
* b:子类重写父类方法时,访问权限不能更低
* 最好就一致
* c:父类静态方法,子类也必须通过静态方法进行重写
* 其实这个算不上方法重写,但是现象确实如此,至于为什么算不上方法重写,多态中体现(静态只能覆盖静态)
* 子类重写父类方法的时候,最好声明一模一样。
* B:Override(重写)和Overload(重载)的区别?Overload能改变返回值类型吗?
* overload可以改变返回值类型,只看参数列表
* 方法重写:子类中出现了和父类中方法声明一模一样的方法。与返回值类型有关,返回值是一致(或者是子父类)的
* 方法重载:本类中出现的方法名一样,参数列表不同的方法。与返回值类型无关。
* 子类对象调用方法的时候:
* 先找子类本身,再找父类。
11.final关键字
* 修饰类,类不能被继承
* 修饰变量,变量就变成了常量,只能被赋值一次
* 修饰方法,方法不能被重写
* A:final修饰变量的初始化时机
* 显示初始化
final int num = 10; //默认初始化是无效值 如果不初始化,就要使用构造函数初始化
* 在对象构造完毕前即可
class Demo{final int num;public Demo{num = 10;}}
12.多态
A:多态中的成员访问特点:
a.成员变量 编译看左边,运行看左边 输出结果为 10 20
b.成员方法 编译看左边,运行看右边(动态绑定) 输出:son
c.静态方法 编译看左边,运行看左边
B:向上转型和向下转型
面试题
public class Test_Polymorphic {public static void main(String[] args) {Fu f = new Zi();f.method(); //编译不通过f.show(); //输出 zi show}
}
class Fu{public void show(){System.out.println("fu show");}
}
class Zi extends Fu{public void show(){System.out.println("zi show");}public void method(){System.out.println("zi method");}
}
public class Test_Polymorphic {public static void main(String[] args) {A a = new B();a.show();B b = new C();b.show();}
}
class A{public void show(){show2();}public void show2(){System.out.println("A");}
}
class B extends A{public void show2(){System.out.println("B");}
}
class C extends B{public void show(){super.show();}public void show2(){System.out.println("C");}
}
输出: B C
13.抽象类
A.抽象类特点
抽象类和抽象方法必须用abstract关键字修饰
抽象类不一定有抽象方法,有抽象方法的类一定是抽象类或者是接口
抽象类不能实例化(由具体的子类实例化,多态的一种)
抽象类的子类,要么是抽象类,要么重写抽象类中的所有抽象方法
B.抽象类的成员特点
成员变量:既可以是变量,也可以是常量 abstract不能修饰成员变量
构造方法:有。用于子类访问父类数据的初始化
成员方法:既可以是抽象的,也可以是非抽象的
抽象方法:强制要求子类做的事情;非抽象方法:子类继承的事情,提高代码复用性
C.注意
一个抽象类可以没有抽象方法,这样做的目的就是不让其他类创建本类对象,交给子类完成
static 和 abstract 不能共存 被abstract修饰的方法没有方法体,被static可以用类名调用,但是类名调用抽象方法没有意义
final 和 abstract 不能共存 被abstract修饰的方法强制子类重写,被final修饰的方法不让子类重写,故矛盾
private 和 abstract 不能共存 被abstract修饰的是为了让子类看到并强制重写,被private修饰的不让子类访问,故矛盾
14.接口 interface 注意:jdk1.8新特性,接口中可以定义方法体,static和default,default可以在子类中不进行重写
A.接口特点
a.接口用关键字interface表示
b.类实现接口用implements表示
c.接口不能实例化
d.接口的子类:可以是抽象类,但意义不大;可以是具体类,要重写接口中的所有抽象方法
B.接口成员特点
成员变量:只能是常量,并且是静态的并公共的 默认修饰符:public static final
构造方法:没有构造方法
成员方法:只能是抽象方法 默认修饰符:public abstract
类与类:继承关系,只能是单继承
类与接口:实现关系,可以单实现,也可以多实现;并且还可以继承一个类的同时实现多个接口
接口与接口:继承关系,可以单继承,也可以多继承
15.四种权限修饰符
本类 同一个包下(子类和无关类) 不同包下(子类) 不同包下(无关类)
private Y
默认 Y Y
protected Y Y Y
public Y Y Y Y
16.内部类 在类中定义类
outer.Inner oi = new outer.Inner();
* A:内部类访问特点
* a:内部类可以直接访问外部类的成员,包括私有。
* b:外部类要访问内部类的成员,必须创建对象。
* 外部类名.内部类名 对象名 = 外部类对象.内部类对象;
* B:private 内部类私有 只能在该外部类提供一个public方法访问
class Demo2_InnerClass {public static void main(String[] args) {//Outer.Inner oi = new Outer().new Inner(); //编译错误//oi.method();Outer o = new Outer();o.print();}
}
class Outer {private int num = 10;private class Inner {public void method() {System.out.println(num);}}public void print() {Inner i = new Inner();i.method();}
}
* C:static outer.inner.print();
面试题:要求:使用已知的变量,在控制台输出30,20,10。
class Outer {public int num = 10;class Inner {public int num = 20;public void show() {int num = 30;System.out.println(num); //30System.out.println(this.num); //20System.out.println(Outer.this.num); //10}}}class InnerClassTest {public static void main(String[] args) {Outer.Inner oi = new Outer().new Inner();oi.show();} }
17.局部内部类(在方法中定义的内部类)
局部内部类访问局部变量必须用final修饰
因为当调用这个方法时,局部变量如果没有用final修饰,他的生命周期和方法的生命周期是一样的,当方法弹栈,这个局部变量也会消失,那么如果局部内部类对象还没有马上消失想用这个局部变量,就没有了,如果用final修饰会在类加载的时候进入常量池,即使方法弹栈,常量池的常量还在,也可以继续使用 (jdk1.8取消) 常量池在方法区
18.匿名内部类 内部类的简化写法
前提:存在一个类或者接口,可以是具体类,也可以是抽象类
格式:new 类名或者接口名(){
重写方法;
}
本质:是一个继承了该类或者实现了该接口的子类匿名对象。
interface Inter {public void print();
}class Outer {class Inner implements Inter {public void print() {System.out.println("print");}}public void method(){//Inner i = new Inner();//i.print();//new Inner().print(); //new Inner()代表子类对象//Inter i = new Inner(); //父类引用指向子类对象new Inter() { //实现Inter接口public void print() { //重写抽象方法System.out.println("print");}}.print();}
}
匿名内部类只针对重写一个方法时使用
面试题:
class Test1_NoNameInnerClass {public static void main(String[] args) {
PersonDemo pd = new PersonDemo (); //如何调用PersonDemo中的method方法呢?//pd.method(new Student());pd.method(new Person() {
分析:Outer 可以直接调用method方法,说明method方法是一个static方法,随后又调用show方法,说明method方法返回值是一个对象
class Test2_NoNameInnerClass {public static void main(String[] args) {//Outer.method().show(); //链式编程,每次调用方法后还能继续调用方法,证明调用方法返回的是对象Inter i = Outer.method();i.show();}
}
//按照要求,补齐代码
interface Inter { void show();
}class Outer { //补齐代码 public static Inter method() {return new Inter() {public void show() {System.out.println("show");}};}
}
更多推荐
Java基础(五)面向对象
发布评论