封装
1 概述
封装是指隐藏对象的属性和实现细节,仅仅对外提供公共的访问方式。
好处:
1、 提高安全性
2、 提高重用性
1.2 private关键字
是一个权限修饰符,用于修饰成员变量和成员函数,被私有化的成员只能在本类中访问。
想要修改只能,对外提供公共的,get和set方法。
1.3 demo1:封装学生
public class Student {
//String name;
//把属性隐藏起来
private String name;
//提供公共的访问方法
//设置公共的赋值方法
public void setName(String n){
name=n;
}
//设置公共的取值方法
public String getName(){
return name;
}
int age;
}
class StDemo{
public static void main(String[] args) {
Student s = new Student();
//不能访问私有的
//s.name="zhangsan";
//System.out.println(s.name);s
//利用setXxx()给属性赋值
s.setName("zhangsan");
//利用getXxx()给属性取值
System.out.println(s.getName());
}
}
1.4 创建对象的流程
Person p = new Person();//短短这行代码发生了很多事情
-
把Person.class文件加载进内存
-
在栈内存中,开辟空间,存放变量p
-
在堆内存中,开辟空间,存放Person对象
-
对成员变量进行默认的初始化
-
对成员变量进行显示初始化
-
执行构造方法(如果有构造代码块,就先执行构造代码块再执行构造方法)
-
堆内存完成
-
把堆内存的地址值赋值给变量p ,p就是一个引用变量,引用了Person对象的地址值
1.5 匿名对象
没有名字的对象,是对象的简化表示形式。
使用场景:
1、 当被调用的对象只调用一次时(多次会创建多个对象浪费内存)
Demo d = new Demo();
d.sleep();
d.game();
//这个d就是对象的名字。
也可以写成:
new Demo().show();//创建了一个对象调方法
new Demo().game();//又创建了一个对象调方法
2. 继承
2.1 概念
继承是面向对象最显著的一个特性。
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。
Java继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类/超类/基类。
这种技术使得复用以前的代码非常容易,能够大大缩短开发周期,降低开发费用。
提高复用性:只要继承父类,就能有一样的功能
class A extends c{ //原来的eat()拿走了 }
class B extends c{ //原来的eat()拿走了 }
class c{
public void eat(){
syso("eat");
}
}
2.2 特点
1、 使用extends关键字
2、 相当于子类把父类的功能复制了一份
3、 java只支持单继承
4、 继承可以传递(爷爷,儿子,孙子的关系)
5、 不能继承父类的私有成员
6、 继承多用于功能的修改,子类可以拥有父类的功能的同时,进行功能拓展
7、 像是is a 的关系
2.3 入门案例
public class TTT {
public static void main(String[] args) {
Zi zi = new Zi();
zi.speak();
System.out.println(zi.skin);
System.out.println(zi.addr);
}
}
class Fu{
String skin="黄种人";
String addr="大成都";
public void speak(){
System.out.println("Fu...speak()");
}
}
//通过extends和父类发生继承关系
//所有父类的功能,子类都可以继承过来,注意不能是private的
class Zi extends Fu{
//什么都不写,能不能把父亲的内容复制一份出来
}
2.4 super关键字
1、 通过super关键字可以使用父类的内容
2、 super代表父类的一个引用对象
3、 如果用,必须出现在调用位置的第一行
2.5 方法的重写
1、 继承后,子类就拥有了父类的功能
2、 那么在子类中,可以添加子类特有的功能也可以修改父类的原有功能
3、 子类中方法签名与父类完全一样(包括方法的返回值,方法名和参数列表,完全一致)时,会发生覆盖/复写操作,相当于修改功能
注意:
1、父类中的私有方法不能被重写
2、子类重写父类方法时,修饰符要大于等于父类修饰符的权限
2.6 继承中的用法
2.6.1 成员变量的使用
局部的,成员的,父类的。
public class Test2_LeiVariable {
public static void main(String[] args) {
Sub2 s= new Sub2();
s.show();
}
}
class Fu2{
int num=20;
}
class Sub2 extends Fu2{
int num;
public void show(){
int num=9;
System.out.println(num);//变量的就近原则
System.out.println(this.num);//调用本类的成员变量,相当于Sub2.num
System.out.println(super.num);//调用父类的成员变量
}
}
2.6.2 成员方法的使用
继承方法,特有方法,重写方法
p
ublic class Test3_LeiMethod {
public static void main(String[] args) {
Sub3 s=new Sub3();
s.testShow();//调用普通方法,
s.eat();//调用重写方法,子类已经重写了父类的方法,从此再用,就是儿子的实现方式
}
}
class Fu3{
public void show(){
System.out.println("Fu...show()");
}
public void eat(){
System.out.println("爸爸吃肉");
}
}
class Sub3 extends Fu3{
//普通方法
public void testShow(){
super.show();//调用父类的eat()
}
//重写方法
//方法签名完全一致的情况就是发生了重写
public void eat(){
System.out.println("儿子吃肉");
}
}
2.6.3 构造方法的使用
1、 子类创建对象时,默认会去访问父类的无参构造方法
2、 在构造方法的第一行,都有一条默认的语句:super();
3、 父类没有无参构造时,可以用super调用父类的其他构造
public class Test4_LeiConstruct {
public static void main(String[] args) {
Sub4 s = new Sub4();//创建子类对象,在调用子类无参构造前,会先去调用父类的无参构造
}
}
class Fu4{
public Fu4(){
System.out.println("Fu4.Fu4()");
}
public Fu4(String name){
System.out.println("Fu.."+name);
}
}
class Sub4 extends Fu4{
public Sub4(){
// super();//默认就存在的,而且在第一行
super("zhangsan");//调用父类中含参的构造方法
System.out.println("Sub4.Sub4()");
}
public Sub4(String name){
this();//调用本类的无参构造
System.out.println("Sub.."+name);
}
}
2.7 拓展
2.7.1 this和super的区别
1、 this代表本类对象的引用,super代表父类对象的引用。
2、 this用于区分局部变量和成员变量
3、 super用于区分本类变量和父类变量
4、 this.成员变量 this.成员方法() this(【参数】)代表调用本类内容
5、 super.成员变量 super.成员方法() super(【参数】),代表调用父类内容
6、 this和super不可以同时出现在同一个构造方法里,他们两个只要出现都得放在第一行,同时出现的话,到底第一行放谁呢。。
2.7.2 重写与重载的区别(Overload和Override的区别)
1、重载:是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
2、重写:是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型
3、重写是父类与子类之间多态性的一种表现
4、重载是一类中多态性的一种表现
2.8.3 继承的内存结构
3 多态
3.1 概念
多态指同一个实体同时具有多种形式。它是面向对象程序设计(OOP)的一个重要特征。
主要是指同一个对象,在不同时刻,代表的对象不一样,指的是对象的多种形态。
好处是可以把不同的子类对象都当作父类来看,可以屏蔽不同子类对象之间的差异,写出通用的代码,做出通用的编程,统一调用标准。
例如:水,在不同时刻可以有多种形态,包括水蒸气,冰,水。
Java怎么体现多态呢?狗有两种形态:狗和小动物
class Animal
class Dog extends Animal
Dog d = new Dog();//狗是狗
Animal a=new Dog();//狗是小动物,创建了狗的对象,赋值给动物对象,这就是多态
3.2 特点
1、 多态的前提是继承
2、 要有方法的重写
3、 父类引用指向子类对象,如:Animal a = new Dog(); – 小到大,向上转型
4、 多态中,编译看左边,运行看右边
3.3 入门案例
public class p {
public static void main(String[] args) {
/*Animal a = new Animal();
a.eat();
Dog d = new Dog();
d.kanjia();
d.eat();*/
//父类引用指向子类对象--把右面的小的,给了左面大的。相当于从小到大的过程,向上造型。
Animal an = new Dog();
an.eat();//只可以用父类的功能,这就统一了调用的标准
//狗吃肉,由于eat()发生了重写,所以父类方法被覆盖掉了
}
}
class Animal{
public void eat(){
System.out.println("大小通吃");
}
}
class Dog extends Animal{
public void kanjia(){
System.out.println("狗可以看家");
}
public void eat(){
System.out.println("狗吃肉");
}
}
3.4 多态的好处
1、 多态可以让我们不用关心某个对象到底是什么具体类型,就可以使用该对象的某些方法。
2、 提高了程序的扩展性和可维护性
public class Q {
public static void main(String[] args) {
//多态--父类引用指向子类对象
Dog a2=new Dog();
Cat a2 = new Cat();
Animal2 a2 = new Dog();
eat(a2);//传入的参数满足条件就可以,运行右面的功能
}
//封装共性方法,不关心具体类型,只要传入的参数是子类就可以
public static void eat(Animal2 a){
a.eat();
}
}
3.5 多态的使用
3.5.1 特点
1、成员变量:使用的是父类的
2、成员方法:由于存在重写现象所以使用的是子类的
3、静态成员:随着对象而存在,谁调用的就返回谁的
3.5.2 测试
public class K {
public static void main(String[] args) {
Fu2 f = new Zi2();//多态,只能用父类的。。。
//多态的成员变量,就是父类的
System.out.println(f.num);//10
//成员方法,因为存在重写,所以是子类的
f.study();//Zi..study()
//静态成员,谁调用就是谁的
System.out.println(f.count);//10
f.sleep();//Fu..sleep()
}
}
class Fu2{
int num=10;
static int count=10;
public void study(){
System.out.println("Fu..study()");
}
public static void sleep(){
System.out.println("Fu..sleep()");
}
}
class Zi2 extends Fu2{
int num=20;
static int count=20;
public void study(){
System.out.println("Zi..study()");
}
public static void sleep(){
System.out.println("Zi..sleep()");
}
}
3.6 拓展
3.6.1 静态代码块,构造代码块,局部代码块 !!!执行顺序:静态代码块—构造代码块—构造函数
1、 静态代码块:在类加载时就加载,并且只被加载一次,一般用于项目的初始化
2、 构造代码块:在创建对象时会自动调用,每次创建对象都会被调用
3、 局部代码块:方法里的代码块
public class haha {
public static void main(String[] args) {
//必须创建对象,不然静态代码块咋随着类的加载而加载。。
Block m = new Block();//静态1 静态2 构造1 构造2 局部1
System.out.println();
Block m2 = new Block();//构造1 构造2 局部1,说明静态代码只被执行一次就是在类第一次初始化时
}
}
class Block{
{
System.out.println("构造1");
}
static{
System.out.println("静态1");
}
public Block(){
{
System.out.println("局部1");
}
}
{
System.out.println("构造2");
}
static{
System.out.println("静态2");
}
}
3.7.2 静态变量和实例变量的区别
在语法定义上的区别:静态变量前要加static关键字,而实例变量前则不加。
在程序运行时的区别:实例变量属于某个对象的属性,必须创建了实例对象,其中的实例变量才会被分配空间,才能使用这个实例变量。静态变量不属于某个实例对象,而是属于类,所以也称为类变量,只要程序加载了类的字节码,不用创建任何实例对象,静态变量就会被分配空间,静态变量就可以被使用了。总之,实例变量必须创建对象后才可以通过这个对象来使用,静态变量则可以直接使用类名来引用。
3.7.3 向上转型和向下转型
在JAVA中,继承是一个重要的特征,通过extends关键字,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
在应用中就存在着两种转型方式,分别是:向上转型和向下转型。
比如:父类Parent,子类Child
向上转型:父类的引用指向子类对象Parent p=new Child();
说明:向上转型时,子类对象当成父类对象,只能调用父类的功能,如果子类重写了父类的方法就根据这个引用指向调用子类重写方法。
向下转型(较少):子类的引用的指向子类对象,过程中必须要采取到强制转型。
Parent p = new Child();//向上转型,此时,p是Parent类型
Child c = (Child)p;//此时,把Parent类型的p转成小类型Child
//其实,相当于创建了一个子类对象一样,可以用父类的,也可以用自己的
说明:向下转型时,是为了方便使用子类的特殊方法,也就是说当子类方法做了功能拓展,就可以直接使用子类功能。