java之面向对象
一.面向对象概述
“面向对象”(英语:Object Oriented,简称OO)是一种以事物为中心的编程思想。
面向对象程序设计(英语:Object-oriented programming,缩写:OOP),是一种程序开发的方法。它将对象作为程序的基本单元,将程序和数据封装其中,以提高软件的重用性、灵活性和扩展性。
SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。面向对象是相对于面向过程而言的(c则是一个典型的面向过程的语言),站在面向对象的角度去看问题,你则是对象的动作的指挥者。如果站在面向过程的角度去看问题,你则是动作的执行者。
对象:在现实生活中存在具体的一个事物。
类:对某种类型事物的共性属性与行为的抽取。
面向对象特征:继承,封装,多态。
二.对象的创建
package com.boxiaoyuan.www; public class Car { private String name = null; public Car(String name) { this.name = name; } public void run() { System.out.println(this.name + "车在跑"); } } package com.boxiaoyuan.www; public class CarDemo { public static void main(String[] args) { Car car = new Car("宝马"); car.run(); } }
成员变量: 定义在类中的变量,在整个类内部有效,属于对象,随着对象的创建而创建,随着对象的消失而消失,存储在堆内,当没有引用指向其实,才进行垃圾回收,如果没有默认值,自动给它赋初始值。
局部变量: 定义在方法中的变量,使用完马上释放空间,存储在栈内存中,当不再使用时,马上会释放,如果想要使用必须手动初始化。
三.匿名对象
匿名对象:没有名字的对象。
1.当对象对方法仅进行一次调用的时候,可以使用匿名对象。
2.匿名对象可以作为实际参数进行传递。
package com.boxiaoyuan.www; public class Car { private String name; private String color; private int num; public Car(String name, String color, int num) { this.name = name; this.color = color; this.num = num; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getColor() { return color; } public void setColor(String color) { this.color = color; } public int getNum() { return num; } public void setNum(int num) { this.num = num; } public void run() { System.out.println(this.name + this.color + this.num + "轮车在跑"); } } package com.boxiaoyuan.www; public class CarDemo { public static void main(String[] args) { CarFactory cFactory = new CarFactory("4S店", "北京市朝阳区"); Car c = cFactory.repareCar(new Car("宝马", "白色", 3) , "黑色", 4); c.run(); } } package com.boxiaoyuan.www; public class CarFactory { private String name; private String address; public CarFactory(String name, String address) { this.name = name; this.address = address; } public Car repareCar(Car c, String color, int num) { c.setColor(color); c.setNum(num); return c; } }
四.封装
如果一个属性不想被其他人直接的访问,那么这个时候就可以使用封装。现实开发中的实体类的成员属性(成员变量)一般都会封装起来。
实体类:用于描述一类事物的类则成为实体类,比如:class Car(),class Student。
五.构造方法
1、一般函数是用于定义对象应该具备的功能。而构造函数定义的是:对象在调用功能之前,在建立时,应该具备的一些内容。也就是对象的初始化内容。
2、构造函数是在对象建立时由jvm调用, 给对象初始化。一般函数是对象建立后,当对象调用该功能时才会执行。(构造方法不是java虚拟机添加的,是java编译器添加的)
3、普通函数可以使用对象多次调用,构造函数就在创建对象时调用。
4、构造函数的函数名要与类名一样,而普通的函数只要符合标识符的命名规则即可。
5、构造函数没有返回值类型。无参的构造函数的权限修饰符是与类名一致的。
注意细节:
1.当类中没有定义构造函数时,系统会自动给该类加上一个空参数的构造函数。这个是类中默认的构造函数。当类中如果自定义了构造函数,这时默认的构造函数就没有了。
2.在一个类中可以定义多个构造函数,以进行不同的初始化。多个构造函数存在于类中,是以重载的形式体现的。因为构造函数的名称都相同。
构造代码块
构造代码块作用:给所有的对象进行统一的初始化。
执行顺序:
基类静态代码块
派生类中的静态代码块
基类代码块
基类无参构造方法
派生类中的代码块
派生类中的无参构造方法
派生类中的方法
package com.boxiaoyuan.www; public class Father { { System.out.println("这是父类代码块"); } static { System.out.println("这是父类静态代码块"); } public Father() { System.out.println("这是父类构造方法"); } } package com.boxiaoyuan.www; public class Son extends Father{ { System.out.println("这是子类代码块"); } static { System.out.println("这是子类静态代码块"); } public Son() { System.out.println("这是子类构造函数"); } } package com.boxiaoyuan.www; public class Demo05 { public static void main(String[] args) { Son son = new Son(); } } -------输出结果-------- 这是父类静态代码块 这是子类静态代码块 这是父类代码块 这是父类构造方法 这是子类代码块 这是子类构造函数
构造代码块要注意的细节:
1构造函数的代码是位于成员变量的显示初始化语句、构造代码块语句之后执行的。
2成员变量的显式初始化语句与构造代码块的语句的先后执行顺序是按照当前代码的顺序执行的。
3成员变量的初始化语句和构造代码块的代码其实是在构造函数中完成的。
六.this
this关键字代表的是对象的引用。
this只能在非静态中(没有static修饰的)的函数中使用
构造函数间相互调用必须放在构造函数的第一个语句中,否则编译错误
可以解决构造函数中对象属性和函数形参的同名问题
七.static
static使用
1:主要用于修饰类的成员
1:成员变量
1:非静态成员变量:需要创建对象来访问
2:静态成员变量:使用类名直接调用,也可以通过对象访问
3:千万不要为了方便访问而使用static修饰一个成员变量,只有这个成员变量的数据是需要被共享的时候才使用static修饰。
2:成员方法
可以使用类名直接调用
1:静态函数:
1:静态函数中不能访问非静态成员变量,只能访问静态变量
2:静态方法不可以定义this,super关键字
3:因为静态优先于对象存在.静态方法中更不可以出现this
4:非静态函数中可以访问静态成员变量
细节:
1:静态函数中可以直接访问静态的成员,但是不能直接访问非静态的成员。
2:非静态函数可以访问静态变量以及非静态的成员。
原因:静态函数可以使用类名调用,而这时候对象可能还没存在内存中,这时候非静态的数据也就不存在了。
3:非静态的函数只能使用对象调用,不能使用类名调用。
原因:非静态函数必须要由对象调用,如果对象存在了,静态数据以及非静态数据早就存在内存中了。
4:静态函数不能出现this以及super关键字。
原因:因为静态函数可以使用类名直接调用,而这时候可能还没有对象存在,this又代表当前对象。
八.继承
1:描述类和类之间的关系
2:降低类和类之间的重复代码
1:降低对象和对象之间的代码重复使用静态变量
2:降低类和类之间的代码重复使用继承
package com.boxiaoyuan.www; public class Person{ private String name; public Person(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public void speak() { System.out.println(this.name+":我是人"); } } package com.boxiaoyuan.www; public class Student extends Person{ public Student(String name) { super(name); } public void study() { System.out.println("姓名:" + this.getName() + ":好好学习,天天向上"); } } package com.boxiaoyuan.www; public class Worker extends Student{ public Worker(String name) { super(name); } public void work() { System.out.println("好好工作,天天挣钱"); } } package com.boxiaoyuan.www; public class Demo04 { public static void main(String[] args) { Student s = new Student("张三"); s.study(); Worker worker = new Worker("李四"); worker.work(); } }
继承细节:
1:类名的设定,被继承的类称之为父类(基类),继承的类称之为子类
2:子类并不能继承父类中所有的成员
1:所有的私有成员不能继承。
2:构造函数不能被继承
子类显式调用父类构造函数:
在子类构造函数第一行通过super关键字调用父类任何构造函数。如果显式调用父类构造函数,编译器自动添加的调用父类无参数的构造就消失。构造函数间的调用只能放在第一行,只能调用一次。super()和this()不能同时存在构造函数第一行。
重写
在继承中,子类可以定义和父类相同的名称且参数列表一致的函数,将这种函数称之为函数的重写。
细节:
1:函数名必须相同
2:参数列表必须相同
3:子类重写父类的函数的时候,函数的访问权限必须大于等于父类的函数的访问权限否则编译报错
4:子类重写父类的函数的时候,返回值类型必须是父类函数的返回值类型或该返回值类型的子类。不能返回比父类更大的数据类型:如子类函数返回值类型是Object
重载和重写的不同:
1:重载(overload):
1:前提: 所有的重载函数必须在同一个类中
2:特点:
函数名相同,参数列表不同,与其他的无关(访问控制符、返回值类型)
3:不同:
个数不同、顺序不同、类型不同
2:重写(override):
1:前提: 继承
2:特点:
函数名必须相同、参数列表必须相同
子类的返回值类型要等于或者小于父类的返回值
九.instanceof
instanceof是什么?
1:属于比较运算符:
2:instanceof关键字:该关键字用来判断一个对象是否是指定类的对象。
3:用法:
对象 instanceof 类;
该表达式是一个比较运算符,返回的结果是boolea类型 true|false
注意:使用instanceof关键字做判断时,两个类之间必须有关系。
十.final
1:final关键字主要用于修饰类、类成员、方法、以及方法的形参。
2.修饰类
当用final修饰一个类时,表明这个类不能被继承。也就是说,如果一个类你永远不会让他被继承,就可以用final进行修饰。final类中的成员变量可以根据需要设为final,但是要注意final类中的所有成员方法都会被隐式地指定为final方法。在使用final修饰类的时候,要注意谨慎选择,除非这个类真的在以后不会用来继承或者出于安全的考虑,尽量不要将类设计为final类。
3.修饰方法
该方法是最终方法,不能被重写,当一个类被继承,那么所有的非私有函数都将被继承,如果函数不想被子类继承并重写可以将该函数final修饰,当一个类中的函数都被修饰为final时,可以将类定义为final的。
4.修饰变量是final用得最多的地方,对于一个final变量,如果是基本数据类型的变量,则其数值一旦在初始化之后便不能更改;如果是引用类型的变量,则在对其初始化之后便不能再让其指向另一个对象。
5.修饰形参
当形参被修饰为final,那么该形参所属的方法中不能被篡改,项目中主要用于一些只用来遍历未知数据的函数。将未知变量声明为final的。增强数据的安全性。
十一.抽象类
抽象类的特点
1:有抽象函数的类,该类一定是抽象类。
2:抽象类中不一定要有抽象函数。
3:抽象类不能使用new创建对象
1:创建对象,使用对象的功能,抽象类的方法,没有方法体。
4:抽象类主要为了提高代码的复用性,让子类继承来使用。
5:编译器强制子类实现抽象类父类的未实现的方法。
1:可以不实现,前提是子类的也要声明为抽象的。
package com.boxiaoyuan.www; public abstract class Animal { private String name; public Animal(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } public abstract void shout(); } package com.boxiaoyuan.www; public class Dog extends Animal{ public Dog(String name) { super(name); } @Override public void shout() { System.out.println("小狗:"+this.getName()+"正在叫。。。。"); } } package com.boxiaoyuan.www; public class Demo05 { public static void main(String[] args) { Dog dog = new Dog("旺财"); dog.shout(); } }
抽象类注意细节
1:如果一个方法没有方法体,那么该方法必须使用abstract修饰。
2:如果一个类有抽象的方法,那么该类也必须使用abstract修饰。
3:非抽象类继承抽象类的时候,必须要把抽象类中的所有抽象方法全部实现。
4:抽象类可以定义抽象方法以及非抽象方法。
5:抽象类是可以不存在抽象方法的(不常用,没意义)。
6:抽象类不能创建对象。
疑问:为什么抽象类不能创建对象?
因为抽象类一旦创建了对象就可以使用对象去调用方法了,一旦调用了抽象方法就没有任何的意义了。
7:抽象类是存在构造方法的。
疑问:既然抽象类不能创建对象,那么存在构造方法的意义在哪?
抽象类的构造方法是留给子类调用初始化从父类继续下去的成员变量的
抽象类可以没有抽象方法(java.awt.*的类就是这样子操作的)。
抽象类可以继承普通类与抽象类。
抽象类一定有构造方法。
abstract与其他修饰符的关系:
final与abstract不能共存:
final:它的作用是修饰类代表不可以继承,修饰方法不可重写
abstract修饰类就是用来被继承的,修饰方法就是用来被重写的。
static修饰的方法可以用类名调用,对于abstract修饰的方法没有具体的方法实现,所有不能直接调用,也就是说不可以与static共存。
private与abstract不能共存:
private修饰的只能在本类中使用,
abstract方法是用来被子类进行重写的,有矛盾
所有不能共存.
十二.接口
接口的特点
1.类实现接口可以通过implements实现,实现接口的时候必须把接口中的所有方法实现,一个类可以实现多个接口。
2.接口中定义的所有的属性默认是public static final的,即静态常量,既然是常量,那么定义的时候必须赋值。
3.接口中定义的方法不能有方法体。接口中定义的方法默认添加public abstract
4.有抽象函数的不一定是抽象类,也可以是接口类。
5.由于接口中的方法默认都是抽象的,所以不能被实例化。
6.对于接口而言,可以使用子类来实现接口中未被实现的功能函数。
7.如果实现类中要访问接口中的成员,不能使用super关键字。因为两者之间没有显示的继承关系,况且接口中的成员属性是静态的。可以使用接口名直接访问。
8.接口没有构造方法。
十三.多态
1:什么是多态
一个对象的多种状态(父类引用类型变量指向了子类对象或者是接口的引用类型变量指向了接口实现类的对象)
2:多态的前提:必须存在继承或者实现关系。
3:多态要注意的细节:
1:多态情况下,子父类存在同名的成员变量时,默认会访问父类的成员变量。
2:多态情况下,子父类存在同名的非静态函数时,默认是访问子类的成员函数。
3:多态情况下,子父类存在同名的静态函数时,默认是访问父类的成员函数。
4:多态情况下,不能访问子类特有的成员。
总结:多态情况下,子父类存在同名的成员时,默认都会访问父类的成员,只有存在非静态的同名函数时,才是访问子类的成员。
多态情况下如果需要调用到子类特有的成员,那么需要进行类型转换。
