This article continues from the previous article:java - Detailed introduction to object-oriented (1)
11. Subclass access to parent class and method override
Subclasses cannot directly access the private members of the parent class;
But the subclass can call non-private methods in the parent class to indirectly access the private members of the parent class.
There is a private field name in the Person class, and Student inherits Person
new Sudent().name;
The subclass extends the parent class (the subclass is a special case of the parent class)
Cause of method override:
The subclass needs to override the parent class method.
12. Super keyword and calling the parent class constructor
Indicates the default reference of the parent class object
If the child If a class wants to call the overridden instance method of the parent class, super can be used as the caller to call the overridden instance method of the parent class.
Use super to call the parent class methodUse super to call the parent class's constructorCalling the constructor
Call another overloaded constructor in this class using this (parameter list)
When a class constructor calls the parent class constructor, use super (parameter list)
When a subclass calls the parent class's constructor:
super must be placed in the first sentence
Java will first call the parameterless constructor of the parent class before executing the constructor of the subclass. The purpose is to initialize the members inherited from the parent class.
When a subclass creates an object, it calls the parent class's no-argument constructor by default. If the subclass constructor explicitly specifies calling other parent class constructors, the specified parent class constructor will be called. , cancel the call to the parent class's parameterless constructor.
Eg: package reviewDemo; class A{ String name; A(){ System.out.println("父类默认隐式的构造方法!"); } A(String name){ System.out.println("父类显式的构造方法!"); } } class B extends A{ B(){ super(null); System.out.println("子类默认隐式的构造方法!"); } } public class Demo10 { public static void main(String[] args) { new B(); } }
13. Object-oriented polymorphism
Polymorphism: refers to the same entity having Various forms
For example, if you go to a noodle shop to eat noodles and say I want noodles, then the boss can give me beef noodles, egg noodles, etc.
This means that "noodles" have Multiple forms, that is to say, entities have multiple forms;
The compile-time type is determined by the type used when declaring the variable, and the run-time type is determined by the object actually assigned to the variable.
Polymorphism occurs if the compile-time type and the run-time type are different.
Eg:
Premise:Student extends Person:
##Person p = new Person();
Student s = new Student();
Person p = new Student();//Polymorphism
The mechanism to implement polymorphism:
The reference variable of the parent class can point to the instance object of the subclass, and the method called by the program is Dynamic binding during runtime refers to the method of the real instance object pointed to by the reference variable, that is, the method of the object running in the memory, rather than the method defined in the type of the reference variable.The role of polymorphism:
Treating different subclass objects as parent classes can shield the differences between different subclass objects and write Universal code and universal programming to adapt to changing needs. Only modify the implementation of the method, not the declaration of the methodInheritance is a prerequisite for polymorphism;
Category:Compile-time polymorphism: method overloadingRun-time polymorphism: method overwritingEg: package test; class Dog{ void eat(){ System.out.println("一般的狗吃一般的狗粮!"); } } class HashDog extends Dog{ void eat(){ System.out.println("哈士奇吃哈士奇的狗粮!"); } } class ZangAoDog extends Dog{ void eat(){ System.out.println("藏獒吃藏獒的狗粮!"); } } //定义一个动物园喂的方法 class Zoo{ void feed(Dog d){ d.eat(); } } public class Demo11 { public static void main(String[] args) { Dog hd = new HashDog(); Dog zd = new ZangAoDog(); Zoo z = new Zoo(); z.feed(hd); z.feed(zd); } }
14. Reference variable type conversion
Upward transformation (subclass → parent class): (automatic completion) Parent class name Parent class object = subclass instance; Downcast (parent class→subclass): (forced completion) Subclass name subclass object = (subclass name) parent class instance;Object name instanceof class Determine whether the actual type referenced by the specified variable name at this time is the currently given class or subclass; My summary: the type of object and Classes must have inheritance relationshipsEg: class A extends B{} B b = new A(); If(b instanceof A){ ... }
2、面向对象(2)
1、基本数据类型的包装类
引言:Java提倡的万物皆对象,但是数据类型的划分出现了基本数据类型和引用数据类型,那么我们怎么能把基本数据类型称为对象呢?
除了Integer和Character定义的名称和对应的基本类型差异大,其他六种都是将首字母大写就可以了。
Integer,Byte,Float,Double,Short,Long都是Number类的子类。(Number类后面讲);
Character和Boolean都是Object直接子类;
8个类都是final修饰的(不可被继承)。
2、基本数据类型和包装类相互转换
把基本数据类型 → 包装类:
通过对应包装类的构造方法实现
除了Character外,其他包装类都可以传入一个字符串参数构建包装类对象。
包装类 → 基本数据类型
包装类的实例方法xxxValue(); // xxx表示包装类对应的基本数据类型
Eg: boolean bool = false; Boolean b2 = new Boolean(bool); Integer i = new Integer(3); int i2 = i.intValue(); Boolean b1 = new Boolean("TRue");//true boolean b2 = b1.booleanValue(); Float f = new Float("3.14");//3.14 Integer i2 = new Integer("123s");//NumberFormatException
备注:
自动装箱&自动拆箱
jdk1.5开始出现的特性:
自动装箱:可把一个基本类型变量直接赋给对应的包装类对象或则Object对象
自动拆箱:允许把 包装类对象直接赋给对应的基本数据类型
Eg: Integer i = 3;//装箱 int i2 = i;//拆箱 Object flag = new Boolean(false); if(flag instanceof Boolean){ Boolean b = (Boolean)flag; boolean b2 = b; }
3、基本类型和String之间的转换
String → 基本类型,除了Character外所有的包装类提供parseXxx(String s)静态方法,用于把一个特定的字符串转换成基本类型变量;
基本类型 → String,String 类有静态方法valueOf(),用于将基本类型的变量转换成String类型。
String str = "17"; int i = Integer.parseInt(str);//String --> 基本类型 String s1 = String.valueOf(i);//基本类型 --> String
4、Object类
所有类的公共父类,一旦一个类没有显示地继承一个类则其直接父类一定是Object。
一切数据类型都可用Object接收
class OOXX extends Object{}等价于class ooXX {}
常见方法
public boolean equals(Object obj)
:对象比较
public int hashCode()
:取得该对象的Hash码
public String toString()
:对象描述
Object类的 toString()方法:“对象的描述”
建议所有类都覆写此方法
直接打印输出对象时,会调用该对象的toString()方法。//可以不写出来
打印对象的时候,实际调用的对象实际指向的类的自我描述;
全限定类名+@+十六进制的hashCode值,等价于
全限定类名+@+IntegertoHexString(该对象.hashCode)
equals也是判断是否指向同一个对象
没有实际意义,有必要可以重写
public boolean equals(Object obj) {}
String 覆写了 Object的equals方法:只比较字符的序列是否相同
==用于判断两个变量是否相等
基本类型:
引用类型:必须指向同一个对象,才true
只能比较有父子或平级关系的两个对象
new String("1") == new String("1"); ?
5、代码块
代码块指的是使用"{}"括起来的一段代码,根据代码块存在的位置可以分为4种:
普通代码块;
构造代码块;
静态代码块;
同步代码块(线程同步的时候讲解)。
代码块里变量的作用域:
只在自己所在区域(前后的{})内有效;
普通代码块:
普通代码块就是直接定义在方法或语句中定义的代码块:
public void show(){
普通代码块
}
构造代码块:
直接写在类中的代码块:
优先于构造方法执行,每次实例化对象之前都会执行构造代码块。
Eg: public class Demo { { System.out.println("我是构造代码块"); } public Demo(){ System.out.println("我是构造方法"); } public static void main(String[] args) { Demo d1 = new Demo(); Demo d2 = new Demo(); } }
静态代码块
使用static 修饰的构造代码块:
优先于主方法执行,优先于构造代码块执行,不管有创建多少对象,静态代码块只执行一次,可用于给静态变量赋值;
Eg: package reviewDemo; /** * 测试各代码块的优先级 * 优先级顺序:静态代码块 > 构造代码块 > 普通代码块 * 备注:无论创建几个对象,静态代码块只执行一次! */ public class Demo13 { Demo13(){ System.out.println("我是构造方法!"); } { System.out.println("我是构造代码块!");//实例化对象的时候才会去调用! } static{ System.out.println("我是静态代码块!"); } public static void main(String[] args) { new Demo13(); new Demo13();//再次创建对象,证明无论创建几次对象,静态代码块都只执行一次 System.out.println("我是普通代码块!"); } }
输出:
我是静态代码块!
我是构造代码块!
我是构造方法!
我是构造代码块!
我是构造方法!
我是普通代码块!
6、构造方法的私有化
有的时候我们为了避免外界创建某类的实例,就将某类的构造方法私有化,即将它的构造方法用private修饰:
外界如何用到?
提供get方法!不提供的话外界就没法创建对象!(对反射无效)
Eg:package reviewDemo; class Stu{ //将构造方法私有化 private Stu(){ } } public class Demo15 { public static void main(String[] args) { Stu s = new Stu(); } }
Singleton模式(单例模式) 饿汉式和懒汉式
目的:整个应用中有且只有一个实例,所有指向该类型实例的引用都指向这个实例。
好比一个国家就只有一个皇帝(XXX),此时每个人叫的“皇帝”都是指叫的XXX本人;
常见单例模式类型:
饿汉式单例:直接将对象定义出来
懒汉式单例:只给出变量,并不将其初始化;
我的总结:
饿汉式,static修饰,随着类的加载而加载,会损耗性能,但是方法相对简单
懒汉式 第一次用的时候相对较慢,因为需要加载!线程,不安全!
package reviewDemo; //单例模式 //饿汉式,直接把对象构造出来 class SingleDemo{ private static SingleDemo s1 = new SingleDemo(); private SingleDemo(){ //提供私有化的构造方法,那么外界就不能构造对象了! } public static SingleDemo getS1() { return s1; } } //懒汉式,先定义,但是不创建对象 class SingleDemo2{ private static SingleDemo2 s3 ; private SingleDemo2(){ //提供私有化的构造方法,那么外界就不能构造对象了! } public static SingleDemo2 getS3() {//这是一个方法,返回值为创建的对象! if(s3 == null){ s3 = new SingleDemo2(); }//和饿汉式的区别,此时才来创建对象! return s3; } } public class Demo14 { public static void main(String[] args) { SingleDemo s1 = SingleDemo.getS1(); SingleDemo s2 = SingleDemo.getS1(); SingleDemo2 s3 = SingleDemo2.getS3(); SingleDemo2 s4 = SingleDemo2.getS3(); System.out.println(s1 == s2); System.out.println(s3 == s4); } } 输出:true true 备注:枚举更加安全些 package reviewDemo; enum Stu{ jake; //将构造方法私有化起来,反射也不能创建对象,安全 private Stu(){ } } public class Demo15 { public static void main(String[] args) { } }
8、final 关键字
final可以修饰类,方法,变量。
final修饰类不可以被继承,但是可以继承其他类。
final修饰的方法不可以被覆写,但可以覆写父类方法。
final修饰的变量称为常量,这些变量只能赋值一次。
内部类在局部时,只可以访问被final修饰的局部变量。
final修饰的引用类型变量,表示该变量的引用不能变,而不是该变量的值不能变;
Eg: package reviewDemo; final class Name{ } class NewName extends Name{//ERROR,报错,因为Name有final修饰 } public class Demo15 { public static void main(String[] args) { } }
9、抽象类
当编写一个类时,我们往往会为该类定义一些方法,这些方法是用来描述该类的行为方式,那么这些方法都有具体的方法体。
但是有的时候,某个父类只是知道子类应该包含怎么样的方法,但是无法准确知道子类如何实现这些方法。
抽象方法的定义:通过abstract关键字来修饰的类称为抽象类;
总结:抽象类用private修饰,里面可以有用private修饰的方法(没有方法体),强制子类进行覆写;
可以理解为:具有某些公共方法的一个总结类。
可以定义被abstract修饰的抽象方法
抽象方法只有返回类型和方法签名,没有方法体。
备注:
抽象类可以含有普通方法
抽象类不能创建实例对象(不能new)
需要子类覆盖掉所有的抽象方法后才可以创建子类对象,否则子类也必须作为抽象类
列举常见的几个抽象类:
流的四个基本父类
InputStream,OutputStream,Reader,Writer
我的总结:
抽象类是类的一种特殊情况:据有类的一切特点,但是不能实例化;一般的都得带有抽象方法。
抽象类不可以实例化,有时看到的近似实例化是多态机制的体现,并不是真正的实例化。
Eg: Socket s = new Socket(); OutputStream os = s.getOutputStream(); 左边是OutputStream类型变量的声明,右边是获取抽象类OutputStream的一个实例对象! package testDemo2; abstract class Person{ } class Student extends Person{ } public class Demo2 { public static void main(String[] args) { Person p = new Student();//体现的是多态,父类声明实例化子类对象。而不是抽象类实例化 } }
abstract方法
分析事物时,发现了共性内容,就出现向上抽取。会有这样一种特殊情况,就是功能声明相同,但功能主体不同。
那么这时也可以抽取,但只抽取方法声明,不抽取方法主体。那么此方法就是一个抽象方法。
abstract [非private访问修饰符] 返回值类型 方法名称(参数列表);
抽象方法要存放在抽象类中。
抽象方法也可以存在于接口中
Eg: package reviewDemo; abstract class Person3{ abstract void show(); abstract void inof(); void turn(){ } } class NewP extends Person3{ @Override void show() { } @Override void inof() { } //不覆写的话会报错 } public class Demo15 { public static void main(String[] args) { //new Person3();报错!因为抽象类不可以实例化 } }
10、抽象类的体现-模板模式
抽象类是多个具体子类抽象出来的父类,具有高层次的抽象性;以该抽象类作为子类的模板可以避免子类设计的随意性;
抽象类的体现主要就是模板模式设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行拓展,但是子类在总体上大致保留抽象类的行为方式;
编写一个抽象父类,该父类提供了多个子类的通用方法,并把一个或多个抽象方法留给子类去实现,这就是模板设计模式;
模板模式应用的简单规则:
1.抽象父类可以只定义需要使用的某些方法,其余留给子类去实现;
2.父类提供的方法只是定义了一个通用算法,其实现必须依赖子类的辅助;
我的总结:
如果父类的方法不想被子类覆写,那么可以在前面加上final关键字修饰。
Eg: package reviewDemo; //模板模式 //抽象类中包含很多的抽象方法,子类必须去覆写! abstract class Method{ abstract double mul();//返回值类型如果是void的话,下面报错,因为没有返回值,无法引用! abstract double divid(); void show(){ System.out.println("面积是:"+mul());//周长 System.out.println("面积是:"+divid());//面积 } } class Square extends Method{ double d; public Square(double d) { super(); this.d = d; } @Override double mul() { return d * d; } @Override double divid() { return 4 * d; } } class Cirle extends Method{ double r; public Cirle(double r) { super(); this.r = r; } @Override double mul() { return 2 * 3.14 * r; } @Override double divid() { return 3.14 * r * r; } } public class Demo16 { public static void main(String[] args) { Square s = new Square(5); s.show(); Cirle c = new Cirle(4); c.show(); } }
以上是本次整理的关于java面向对象的详细讲解,后续会为大家继续整理。
文中若有明显错误请指正,谢谢!
For more JAVA related questions, please visit the PHP Chinese website: JAVA Video Tutorial
The above is the detailed content of Java——Detailed introduction to object-oriented (2). For more information, please follow other related articles on the PHP Chinese website!