目录
一、什么是面向对象
1、面向过程
步骤清晰简单;适合处理一些较为简单的问题
2、面向对象
- 物以类聚,分类的思维方式,思考问题首先会解决问题需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向过程的思索
- 适合处理复杂的问题,适合处理需要多人协作的问题
(1)面向对象编程 (Object-Oriented Programming,OOP)
(2)面向对象编程的本质:以类的方式组织代码,以对象的组织封装数据
(3)特性:封装、继承、多态
(4)类与对象
- 从认识论角度考虑,先有对象后又类。对象是具体是事务,类是对对象的抽象
- 从代码运行角度考虑,先有类后有对象。类是对象的模板
二、值传递 与 引用传递
1、值传递:不改变变量内容
// 值传递
public class demo01 {
public static void main(String[] args) {
int a = 1;
System.out.println(a); //1
value(a);
System.out.println(a); //1
}
public static void value(int a){
a = 10;
}
}
2、引用传递:改变变量内容
// 引用传递:对象。但本质还是值传递
public class demo02 {
public static void main(String[] args) {
Person person = new Person(); // 实例化对象
System.out.println(person.name); //null
demo02.change(person);
System.out.println(person.name); //安然
}
public static void change(Person person){
person.name = "安然";
}
}
class Person{
String name;
}
三、类 与 对 象
1、区别
- 类是一种抽象的数据类型,是对某一类事物整体描述,不能代表某一个具体的事物
例:Person类,Pet类
- 对象是抽象概念的具体实例
例:张三是Person类的一个具体实例
2、创建对象
- 使用new关键字创建对象
- 类名 对象名 = new 类名(参数);
- 使用new创建对象时,除分配内存空间外,还会给其进行默认初始化以及类中构造器(构造方法)的调用
- 构造器(构造方法)必须和类名相同,没有返回类型,但不写void
四、构 造 器
1、构造器 / 方法:实例化初始值
2、使用new关键字,本质是在调用构造器
3、有参构造
public 类名(参数类型 变量名){
方法体
}
4、无参 / 默认 构造
public 类名 (){
}
5、一旦定义了有参构造,若还要对象使用无参构造,则必须在类中显式定义无参构造
6、IDEA自动生成构造器快捷键:Alt + Insert
五、封 装
1、通俗来讲,封装是将类的属性私有化,禁止对象直接更改,但类中定义了set( ) 和 get( ) 方法,可通过这两种方法来间接更改私有属性值
2、作用
(1)提高了程序的安全性,保护数据;
(2)隐藏代码的实现细节;
(3)统一接口
(4)增加了系统可维护性
public class demo03 {
public static void main(String[] args) {
Student student = new Student();
student.setName("安然");
System.out.println(student.getName());
}
}
class Student{
private String name; //私有属性
public void setName(String name){ //定义私有属性
this.name = name;
}
public String getName(){ //返回私有属性
return this.name;
}
}
六、继 承
1、类与类间可以继承,形成父子关系。子类继承了父类中除private中的所有属性和方法,并且可以对父类方法进行重写,也叫做覆盖,此外,子类还可以定义其属性和方法。因此,子类又叫做派生类
2、语法规则
类修饰符 子类名 extends 父类名 { }
3、Java中所有的类都默认继承Object类
4、在子类中可以用super来表示父类的某个方法或属性,用法与this相同
七、super关键字
1、在子类中调用父类方法
public class demo04 {
public static void main(String[] args) {
Student1 student1 = new Student1();
student1.printName();
}
}
class Person1{
String name = "AnRan"; //父类name属性
public void print(){ //父类print方法
System.out.println("父类属性name为:" + name);
}
}
class Student1 extends Person1{
String name = "安然"; //子类name属性
public void print(){ //子类重写print方法
System.out.println("子类属性name为:" + name);
}
public void printName(){ //子类printName方法
print();
this.print();
super.print();
}
}
结果
子类属性name为:安然
子类属性name为:安然
父类属性name为:AnRan
2、创建子类对象时,会先调用父类的构造方法,再调用子类的构造方法
public class demo05 {
public static void main(String[] args) {
Student2 student2 = new Student2();
}
}
class Person2{
public Person2(){ //父类构造方法
System.out.println("Person2类构造方法");
}
}
class Student2 extends Person2{
public Student2(){ //子类构造方法
System.out.println("Student2类构造方法");
}
}
结果
Person2类构造方法
Student2类构造方法
注意
- 父类的无参构造器默认是调用的
- 用 super 调用父类的构造方法时,必须在子类构造方法的第一行
- super 只能出现在子类的方法或构造方法中
- super和this不能同时调用构方法(两者都要求必须在第一行,同时出现会起冲突)
- super 只能在继承条件下使用
- this(); 表示本类的构造,super(); 表示父类的构造
八、方法重写 / 覆盖
1、重写
- 需要有继承关系,子类重写父类的方法
- 方法名必须相同
- 参数列表必须相同
- 修饰符可以扩大但不能被缩小 public > protected > default > private
- 静态方法不能被重写,只能被继承
2、静态与非静态方法:静态方法是类的方法,非静态方法是对象的方法
public class demo06 {
public static void main(String[] args) {
A a = new A();
B b = new A();
a.text();
b.text();
}
}
// 没有 static 时,b 调用的是对象的方法,而b是由 A 类 new 的
class B{
public void text(){
System.out.println("B的text");
}
}
class A extends B{
public void text(){
System.out.println("A的text");
}
}
public class demo07 {
public static void main(String[] args) {
C c = new C();
D d = new C();
c.text(); // C的text
d.text(); // D的text
}
}
// 有 static时,d 调用了 D 类的方法,因为 d 是用 D 类定义的
class D{
public static void text(){
System.out.println("D的text");
}
}
class C extends D{
public static void text(){
System.out.println("C的text");
}
}
九、多 态
一个对象的实际类型是确定的
new Father();
new Son();
可以指向的引用类型就不确定了
Son s = new Son();
Father f = new Son(); // 父类的引用指向子类
- 多态是方法的多态,属性没有多态
- 引用类型和实际类型之间要有联系——本身 / 继承
- 多态存在条件:继承关系、方法重写,父类引用指向子类对象
注意:static方法,final方法、private方法不能被重写
十、 instanceof关键字 和 类型转换
1、instanceof
A 对象名称 = new B(); // A与B要么类型相同,要么A为父类,B为子类
对象名称 instanceof C;
- 若A与C有关系,则编译正确;否则,编译错误
- 若B与C有关系,则该句结果为true;否则,结果为false
public class demo08 {
public static void main(String[] args) {
// Object > Person3 > Teacher3
// Object > Person3 > Student3
// Object > String
Object object = new Student3();
System.out.println(object instanceof Student3); //true
System.out.println(object instanceof Person3); //true
System.out.println(object instanceof Object); //true
System.out.println(object instanceof Teacher3); //false
System.out.println(object instanceof String); //false
System.out.println("*************************");
Person3 person3 = new Student3();
System.out.println(person3 instanceof Student3); //true
System.out.println(person3 instanceof Person3); //true
System.out.println(person3 instanceof Object); //true
System.out.println(person3 instanceof Teacher3); //false
//System.out.println(person3 instanceof String); //编译错误
System.out.println("*************************");
Student3 student3 = new Student3();
System.out.println(student3 instanceof Student3); //true
System.out.println(student3 instanceof Person3); //true
System.out.println(student3 instanceof Object); //true
//System.out.println(student3 instanceof Teacher3); //编译错误
//System.out.println(student3 instanceof String); //编译错误
}
}
class Person3{
}
class Teacher3 extends Person3{
}
class Student3 extends Person3{
}
2、类型转换
(1)高 —> 低:将父类对象转换为子类,以便调用子类方法等
Person obj = new Student();
( (Student) obj ).go(); // 父类Person对象 obj 调用子类Student的go方法
(2)低 —> 高:自动进行,但可能会丢失自己本来的一些方法
Student student = new Student(); // 创建子类对象
student.go(); // 调用子类方法
Person person = student; // 将子类对象转换为父类对象
十 一、static关键字
1、静态变量(多线程中常用)可直接用类名进行调用
2、静态方法
- 可通过类名直接调用
- 若在同一类中,还可以直接写方法名来调用
- 静态方法只能调用静态方法
3、匿名代码块、静态代码块、构造方法的执行顺序
- 先执行静态代码块,再执行匿名代码块,最后执行构造方法
- 若创建多个对象,静态代码块只执行一次
- 匿名代码块多用来赋初值
public class demo09 {
public static void main(String[] args) {
Human human1 = new Human();
System.out.println("--------------");
Human human2 = new Human();
}
}
class Human{
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public Human(){
System.out.println("构造方法");
}
}
结果:
3、静态导入包的方法 / 属性:导入后可直接写方法名进行调用,而不必再写类名
import static java.lang.Math.random;
import static java.lang.Math.PI;
public class demo10 {
public static void main(String[] args) {
System.out.println(random());
System.out.println(PI);
}
}
十 二、抽象类
1、抽象类(abstract)的所有抽象方法,必须由其子类(非抽象类)来实现
2、不能new抽象类,只能靠其子类来实现
3、抽象类中可以写普通方法,也可以没有抽象方法
4、抽象方法必须在抽象类中,即存在抽象方法的类一定是抽象类
5、抽象类可以声明并定义构造方法,用来初始化抽象类内部声明的通用变量,也支持默认无参构造方法
6、调用抽象类的非抽象方法时,需通过子类重写
public class demo11 {
public static void main(String[] args) {
//AB ab = new AB(); 编译错误
ABC abc = new ABC(); //创建子类对象
abc.succeed(); //调用抽象方法
abc.out(); //调用非抽象方法
}
}
// 抽象类AB
abstract class AB {
int num;
// 构造方法
public AB() {
num = 10;
}
// 普通方法
public void out(){
System.out.println("=====");
}
// 抽象方法
public abstract void succeed();
}
// ABC类继承了抽象类AB,并实现了其抽象方法
class ABC extends AB {
// 实现抽象方法succeed()
public void succeed(){
System.out.println("------");
}
// 重写方法out()
public void out(){
super.out();
}
}
十 三、接口
1、只能声明方法,不能实现
2、约束和实现分离:面向接口编程
3、关键字:interface;实现接口:implements
4、接口中的所有定义都是抽象的,方法默认为public abstract,故可不写
5、实现了接口的类必须重写接口中的方法
6、接口是多继承的,用逗号区分
7、接口中默认属性为常量 public static final
8、接口不能被实例化,没有构造方法
接口
public interface UserService {
//常量 public static final
int AGE = 99;
// 接口中所定义的方法都是抽象的 public abstract
public abstract void add();
void delete();
void update();
void query();
}
实现类
public class UserServiceImpl implements UserService{
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void update() {
}
@Override
public void query() {
}
}
十 四、内部类
1、成员内部类
(1)在一个类中定义的类叫做成员内部类
(2)可以访问外部类的私有属性
// 外部类
public class Outer {
private int id = 10;
public void out(){
System.out.println("这是外部类的方法");
}
// 内部类
public class Inner{
public void in(){
System.out.println("这是内部类的方法");
}
// 获得外部类的私有属性
public void getID(){
System.out.println(id);
}
}
}
(3)通过外部类来实例化内部类
public class demo12 {
public static void main(String[] args) {
Outer outer = new Outer(); //创建外部类对象
outer.out(); // 调用外部类方法
//通过外部类 实例化内部类
Outer.Inner inner = outer.new Inner();
// 调用内部类方法
inner.in();
inner.getID();
}
}
2、静态内部类
与成员内部类相似,但定义为static,且不能访问外部类中非静态属性和方法
3、局部内部类
在方法中定义的类
4、匿名内部类
创建对象时,没有名字初始化 类 / 接口
public class demo13 {
public static void main(String[] args) {
//匿名内部类
new Apple().eat();
new UserSer(){
public void hello(){
System.out.println("hello");
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserSer{
public void hello();
}
结果: