面向对象编程
对于描述复杂的事物,为了从宏观上把握、从整体上合理分析,需要用面向对象的思路来分析整个系统。在微观上操作时,仍是使用面向过程进行处理。
面向对象编程OOP
面向对象的本质:以类的方式组织代码,以对象的形式封装数据。
三大特征:
- 封装
- 继承
- 多态
方法的定义:
- 修饰符
- 返回类型(和return相对应)
- 方法名
- 参数
- 异常
方法的调用:
- 静态方法
- 非静态方法
- 形参和实参
- 值传递和引用传递
- this关键字
package com.oop.demo;
public class Demo1 {
public static void main(String[] args) {
//方法一
Student student = new Student();
student.say();
//方法二
new Student().say();
int a = 1;
System.out.println(a);
c(a);
System.out.println(a);
}
//和类一起加载
public static void a() {
}
//类实例化后才存在
public void b() {
}
//值传递
public static void c(int a) {
a = 10;
}
}
Studen.java
package com.oop.demo;
public class Student {
//非静态方法
public void say() {
System.out.println("hello");
}
}
引用传递
package com.oop.demo;
public class Demo2 {
//引用传递
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
change(person);
System.out.println(person.name);
}
public static void change(Person person) {
person.name = "abc";
}
}
class Person {
String name;
}
类和对象
类是一种抽象的数据类型,是对一类事物的描述,不代表某一具体事物
对象是对抽象概念的具体实例
使用new关键字来创建对象,进行分配内存空间,进行默认初始化,以及对类中构造器进行调用。
Student.java
package com.oop.demo2;
public class Student {
//属性:字段
String name;
int age;
//方法
public void study() {
System.out.println(this.name + "在学习");
}
}
Application.java
package com.oop.demo2;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
//类是抽象的,需要实例化
//student为Student的一个具体实例
Student student = new Student();
student.name = "Mk";
student.age = 20;
System.out.println(student.name);
System.out.println(student.age);
student.study();
}
}
小结:
-
类是一个模板,对象是一个具体实例
-
方法的定义和调用
-
对象是通过引用来操作的:栈--->堆
-
属性默认初始化
-
使用new关键字来创建对象,注意构造器的使用
-
类:
静态的属性:属性
动态的行为:方法
构造器
使用new时,本质是在调用构造器(构造方法),构造器一般用于调用初始化值
构造器(构造方法):
- 与类名同名
- 没有返回值
作用:
- new本质在调用构造器
- 初始化值
注意:
- 一旦定义了有参构造,无参构造必须显式定义
Person.java
package com.oop.demo2;
public class Person {
String name;
//IDEA中的快捷键 alt+insert产生构造方法
public Person() {
}
public Person(String name) {
this.name = name;
}
}
Application.java
package com.oop.demo2;
//一个项目应该只存在一个main方法
public class Application {
public static void main(String[] args) {
Person person = new Person();
System.out.println(person.name);
Person person1 = new Person("Mk");
System.out.println(person1.name);
}
}
创建对象时的内存分析
Pet.java
package com.oop.demo3;
public class Pet {
String name;
int age;
public void shout() {
System.out.println("汪汪汪");
}
}
Application.java
package com.oop.demo3;
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "abcd";
dog.age = 1;
dog.shout();
}
}
封装
程序设计追求“高内聚,低耦合”
- 高内聚:类的内部数据操作自己完成,不允许外部干涉
- 低耦合:仅暴露少量方法给外部使用
封装(隐藏数据):禁止直接访问一个对象中实际的数据,而是通过操作接口
属性私有,get/set方法
封装作用:
- 提高程序安全性,保护数据
- 隐藏代码实现的细节
- 统一接口
- 系统可维护增加
Student.java
package com.oop.demo4;
public class Student {
//属性私有
private String name;//名字
private int id;//学号
private String sex;//性别
private int age;//年龄
//提供可操作私有属性的方法
//提供public的get、set方法,alt+insert快捷键
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 120 || age < 0) {
this.age = 1;
} else {
this.age = age;
}
}
}
Application.java
package com.oop.demo4;
public class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("Mk");
s1.setAge(12);
System.out.println(s1.getName());
}
}
继承
关键字:extends
Java中为单继承,无多继承。继承是类与类之间的关系,私有的private无法被继承
在Java中,所有类都直接或间接继承自Object类
IDEA中,ctrl+h可查看继承结构
Person.java
package com.oop.demo5;
public class Person {
private int money;
public void say () {
System.out.println("hello");
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
}
Student.java
package com.oop.demo5;
public class Student extends Person {
}
Application.java
package com.oop.demo5;
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.say();
}
}
super
- 调用父类构造方法时,需在子类构造方法的第一个,先调用父类的构造器,后调用子类的构造器
- super只能在方法或构造方法中
- super和this不能同时调用构造方法
super和this区别:
-
代表对象不同:
super代表父类 this代表本类
-
前提:
super仅在继承下使用
this无继承也可使用
-
构造方法
this():本类构造
super():父类的构造
Person.java
package com.oop.demo5;
public class Person {
//无参构造
public Person() {
System.out.println("Person无参构造");
}
protected String name = "a";
}
Student.java
package com.oop.demo5;
public class Student extends Person {
private String name = "b";
public Student() {
//默认调用了父类的无参构造
//super()被隐藏,先调用父类的构造器,后调用子类的构造器
System.out.println("Student的无参构造");
}
public void test() {
System.out.println(name);
System.out.println(this.name);
System.out.println(super.name);
}
}
Application.java
package com.oop.demo5;
public class Application {
public static void main(String[] args) {
Student student = new Student();
}
}
方法重写
重写是方法的重写,和属性无关
IDEA快捷键:alt+insert :-->Override
重写:需要有继承关系,子类重写父类的方法
- 方法名相同
- 参数列表相同
- 修饰符的范围仅能扩大,不能缩小。public > protected > default > private
- 抛出异常时范围可缩小
B.java
package com.oop.demo6;
public class B {
public static void test () {
System.out.println("B>test");
}
}
A.java
package com.oop.demo6;
public class A extends B {
public static void test() {
System.out.println("A>test");
}
}
Application.java
package com.oop.demo6;
public class Application {
public static void main(String[] args) {
//静态方法:方法的调用仅和定义的类型有关
A a = new A();
a.test();
//父类的调用指向了子类
B b = new A();
b.test();
}
}
结果:
B.java
package com.oop.demo6;
public class B {
public void test () {
System.out.println("B>test");
}
}
A.java
package com.oop.demo6;
public class A extends B {
//Override:重写
@Override //注解 alt+insert
public void test() {
System.out.println("A>test");
}
}
Application.java
package com.oop.demo6;
public class Application {
public static void main(String[] args) {
//静态方法:方法的调用仅和定义的类型有关
//非静态方法:重写
A a = new A();
a.test();
//父类的调用指向了子类
B b = new A();
b.test();
}
}
结果:
多态
利用多态实现可扩展性,动态编译
对象能执行哪些方法,主要看引用类型,和new的关系不大
多态存在条件:
- 有继承关系
- 子类重写父类
- 父类引用指向子类对象
多态小结:
- 多态是方法的多态,和属性无关
- 父类子类可进行强制转换
- 父类引用指向子类时,父类不能调用子类独有的方法
-
static方法不能重写
-
final为常量
-
private方法私有,不能重写
Person.java
package com.oop.demo7;
public class Person {
public void run() {
System.out.println("Person");
}
}
Student.java
package com.oop.demo7;
public class Student extends Person {
@Override
public void run() {
System.out.println("Student");
}
public void eat() {
System.out.println("eat");
}
}
Application.java
package com.oop.demo7;
public class Application {
public static void main(String[] args) {
//一个对象的实际类型确定后(new),引用时可指向自身的父类
//s1能调用自己的方法和重写的父类的方法
Student s1 = new Student();
//s2不能调用子类独有的方法,父类引用指向子类
Person s2 = new Student();
Object s3 = new Student();
s1.run();
s2.run();
//s2.eat();不能调用子类独有的方法
((Student) s2).eat();//强制转换
}
}
结果:
instanceof和类型转换
父类和子类,类似于基本数据类型中的高和低数据关系(double和int)
低转高时,自动转换;高转低时需要强制转换
Application.java
package com.oop.demo8;
public class Application {
public static void main(String[] args) {
//instanceof
Object object = new Student();
System.out.println(object instanceof Object);
System.out.println(object instanceof Person);
System.out.println(object instanceof Student);
System.out.println(object instanceof String);
//类型转换
//子类转换为父类会丢失自己独有的方法
//高 低
Person student = new Student();
//强制转换
Person p = new Person();
Student s = (Student) p;
Student student1 = new Student();
//子类转换为父类时自动转换
Person person = student1;
}
}
static
非静态方法可调用静态方法,静态方法可调用静态方法,静态方法不可调用非静态方法
Person.java
package com.oop.demo9;
public class Person {
{//第二次执行,可用来赋初始值
System.out.println("匿名代码块");
}
static { //只执行一次,第一次执行
System.out.println("静态代码块");
}
public Person() {
System.out.println("构造方法");
}
}
Application.java
package com.oop;
import com.oop.demo9.Person;
public class Application {
//一个项目有一个主方法main
public static void main(String[] args) {
Person person = new Person();
System.out.println("==========================");
Person person1 = new Person();
}
}
结果:
静态导入包:
package com.oop.demo9;
//静态导入包
import static java.lang.Math.random;
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());
System.out.println(random());
}
}
抽象类
关键字:abstract
特点:
- 不能进行new实例化,仅能用子类来实现
- 抽象类中可以由抽象方法,也可有普通方法
- 抽象方法仅能存在在抽象类中
抽象类也有抽象方法
Action.java
package com.oop.demo10;
//抽象类,也可以有普通的方法
public abstract class Action {
public Action () {
System.out.println("Action");
}
//用在方法上,进行约束,无方法实现
public abstract void doSomething();
public void run () {
System.out.println("run");
}
}
A.java
package com.oop.demo10;
//抽象类中的抽象方法必须全部实现
public class A extends Action {
@Override
public void doSomething() {
}
}
Application.java
package com.oop;
import com.oop.demo10.A;
public class Application {
public static void main(String[] args) {
A a = new A();
a.run();
}
}
接口
- 普通类:只要具体实现
- 抽象类:具体实现和抽象方法
- 接口:只有规范,实现约束和实现分离
接口关键字:interface、implements
作用:
- 约束
- 定义方法来让不同人实现
- 方法为public abstract
- 属性为public static final
- 接口不能被实例化,接口中没有构造方法
- 可以用implements实现多个接口
- 必须重写接口中的方法
TimeService.java
package com.oop.demo11;
public interface TimeService {
void timer();
}
UserService.java
package com.oop.demo11;
//接口都需要有实现类
public interface UserService {
//接口中所有方法的定义都是public abstract
void add(String name);
void delete(String name);
void update(String name);
void query(String name);
//接口中的属性 public static final
int a = 3;
}
UserServiceImp.java
package com.oop.demo11;
public class UserServiceImp implements UserService, TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void update(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
内部类
Outer.java
package com.oop.demo12;
public class Outer {
private int id = 1;
public void out () {
System.out.println("外部类");
}
public class Inner{
public void in () {
System.out.println("内部类");
}
//用内部类访问外部类的私有属性、方法
public void getId () {
System.out.println(id);
}
}
}
Application.java
package com.oop;
import com.oop.demo12.Outer;
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
//通过外部类来实例化内部类
Outer.Inner inner = outer.new Inner();
inner.in();
inner.getId();
}
}
局部内部类
package com.oop.demo12;
public class Outer2 {
public void method () {
//局部内部类
class Inner {
public void in () {
}
}
}
}
匿名内部类
package com.oop.demo12;
public class Test {
//没有名字初始化类,不用将名字保存在变量中
public static void main(String[] args) {
new Apple().eat();
/*
UserService userService = new UserService() {
@Override
public void hello() {
}
};
*/
new UserService() {
//匿名内部类
@Override
public void hello() {
}
}
}
}
class Apple {
public void eat () {
System.out.println("Apple");
}
}
interface UserService {
void hello();
}