面向过程思想
面向对象思想
对于描述复杂的事物,为了宏观上把握、整体上合理分析,我们需要面向对象的思路来分析整个系统。但是,具体到微观才做,仍然需要面向过程的思想去处理。
面向对象编程(Object-Oriented Programming,OOP)
面向对象的本质是:以类的方式组织代码,以对象的组织(封装)数据
三大特性:封装、继承、多态
静态的方法
//和类一起加载的
public static void a(){}
非静态的方法
//类实例化后才存在
public void b(){}
形参和实参
public class methodDemo {
public static void main(String[] args) {
int result = sum(2,3.14);// 实参与形参的数据类型要对应
}
public static int sum(int a, double b) {// 形式参数
return a + (int)b;
}
}
值传递
public class Demo02 {
public static void main(String[] args) {
int a = 1;
System.out.println(a);// 打印当前a的值为1
change(a);// 传入实参a为1,执行change方法后a=10,但并未返回a的值
System.out.println(a);// 当前a仍为1
}
public static void change(int a) {
a = 10;
}
}
执行结果:
1
1
引用传递
public class Demo03 {
public static void main(String[] args) {
Cat cat1 = new Cat();// 实例化一个Cat类的cat1对象
System.out.println(cat1.name);
System.out.println(cat1.sex);
System.out.println(cat1.age);
cat1.name = "coco";
cat1.sex = "公";
cat1.age = 1;
System.out.println(cat1.name);
System.out.println(cat1.sex);
System.out.println(cat1.age);
Demo03.change(cat1);
System.out.println(cat1.name);
System.out.println(cat1.sex);
System.out.println(cat1.age);
}
public static void change(Cat cat) {
// cat是一个Cat类的对象(形参),可以改变其属性
cat.name = "果冻";// cat. 指向的是Cat类的属性--->Cat cat1 = new Cat();
cat.sex = "母";
cat.age = 3;
}
}
/* 定义了一个Cat类,其中有name、sex、age这三个属性 */
class Cat {
String name;// 默认为null
String sex;
int age;// 默认为0
}
执行结果:
null
null
0
coco
公
1
果冻
母
3
this关键字(指代当前类)
注意点:
加载的顺序问题:
静态方法是在类加载的时候就创建好了,而非静态方法是伴随着对象的创建才创建
类是一种抽象的数据类型,它是对某一事物整体描述/定义,但是不能代表某一个具体的事物
对象是抽象概念的具体实例
使用new关键字创建对象
使用new关键字创建对象时,除了分配内存空间,还会给创建好的对象进行默认的初始化以及对类中构造器的调用
类中的构造器也称为构造方法,是在进行创建对象的时候必须要调用的。
构造器的特点:
构造器的作用:
1. new本质上是在调用构造器
2. 初始化对象(属性)的值
注意点::一旦定义了有参构造,如果想使用无参构造,必须显示定义无参构造
构造器快捷键:alt+insert
一个类即使什么都不写,它也会存在一个方法(构造器)
【演示】
public class Student {
// 定义属性name、sex、age
String name;
String sex;
int age;
/* 无参构造 */
public Student() {
this.name = "张三";// this关键字指当前类,即Student类
this.sex = "男";
this.age = 18;
}
/* 有参构造 */
public Student(String name, String sex, int age) {
this.name = name;// this.name中的name指的是Student类中的String name,后面的name是传进来的参数
this.sex = sex;
this.age = age;
}
// 定义方法status
public void status(String name) {
if (name == "张三"){
System.out.println(this.name+"在学习");
}
if (name == "李四"){
System.out.println(this.name+"在睡觉");
}
}
}
public class Application {
public static void main(String[] args) {
/*
使用new关键字,其本质是在调用构造器
所以必须要有构造器
*/
Student student1 = new Student();// 调用的是无参构造方法
System.out.println(student1.name);
System.out.println(student1.sex);
System.out.println(student1.age);
Student student2 = new Student("李四", "女", 16);// 调用的是有参构造方法
System.out.println(student2.name);
System.out.println(student2.sex);
System.out.println(student2.age);
student1.status("张三");
student2.status("李四");
}
}
执行结果:
张三
男
18
李四
女
16
张三在学习
李四在睡觉
【演示】
public class Pet {
String name;
int age;
public void shut() {
System.out.println("叫了一声");
}
}
public class Application {
public static void main(String[] args) {
Pet dog = new Pet();
dog.name = "旺财";
dog.age = 3;
dog.shut();
Pet cat = new Pet();
}
}
【内存分析】
封装是将内部信息隐藏,对外暴露接口让使用者去调用
封装的关键
封装的好处
【演示】
public class Student {
/* 属性私有 */
private String name;// private修饰的变量作用域仅在本类
private char sex;
private int age;
// get 获得这个属性的值
public String getName() {
return name;
}
// set 给这个属性设置值
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age > 100 || age < 0){
System.out.println("年龄设置不合法");
}else{
this.age = age;
}
}
}
public class Application {
public static void main(String[] args) {
Student student1 = new Student();
student1.setName("张三");
student1.setSex(‘男‘);
student1.setAge(20);
System.out.println(student1.getName());
System.out.println(student1.getSex());
System.out.println(student1.getAge());
}
}
执行结果:
张三
男
20
继承的本质是对某一批类的抽象
继承的关键字是 `extends
Java中只有单继承,没有多继承(一个孩子只能有一个亲生父亲,而一个父亲可以有多个孩子)
【演示】
/* Person类:父类(基类)*/
public class Person {
private String job; // 这个属性是私有的,其子类不能继承
public String name = "中国人";// 这个属性是公共的,其子类可以继承
// 这个方法其子类也可以继承
public void print() {
System.out.println("Person");
}
}
/* Teacher类:子类(派生类)Teacher是一个Person */
public class Teacher extends Person{
public String name = "张三";
public void print(String name) {
System.out.println(name);// 这个name是传进来的参数
System.out.println(this.name);// 这个name是本类中的name张三
System.out.println(super.name);// 这个name是父类中的name中国人
}
public void print() {
System.out.println("Teacher");
}
public void test() {
print();// 指本类中的print方法
this.print();// 指本类中的print方法
super.print();// 指父类中的print方法
}
}
public class Application {
public static void main(String[] args) {
Teacher teacher = new Teacher();
teacher.print("李四");
teacher.test();
}
}
执行结果:
李四
张三
中国人
Teacher
Teacher
Person
通过看类之间的关系发现(ctrl+h),任何类都会默认继承Object类(Java.lang.Object)
一个类中即使不写任何语句,也会有可以调用的方法,因为这些类默认继承Object类,所以这些方法都来自Object类
注意:若Student类继承了Person类,尽管Student类中没有写任何代码,但是Student类继承了Person类中的可继承的属性以及方法,Student类中默认有其无参构造方法且默认其中第一个语句是person类的无参构造方法super(),即Student类中的无参构造方法中包含父类的无参构造方法并且父类的无参构造方法在子类无参构造方法中的第一个语句。
【演示】
/* Person类:父类(基类)*/
public class Person {
/* 父类无参构造方法 */
public Person() {
System.out.println("父类无参构造方法执行");
}
/* 父类有参构造方法 */
public Person(String name) {
System.out.println(name);
}
}
/* Student类:子类(派生类)*/
public class Student extends Person{
public Student() {
/*
隐藏代码:super();调用父类的无参构造方法
注意:这段代码必须在子类无参构造方法的第一句
*/
//super();
//super("I love China!");
System.out.println("子类无参构造方法执行");
}
}
public class Application {
public static void main(String[] args) {
Student student = new Student();//new Student()时会自动调用Student无参构造
}
}
执行结果:
父类无参构造方法执行
子类无参构造方法执行
【解释】:若父类中只定义了有参构造方法,没有显示定义无参构造方法,那么子类的无参构造方法就会报错:没有默认的构造方法可用。因为子类默认的无参构造方法中的第一条语句时super();(这句代码是隐藏的,默认存在)super()指的是父类的无参构造方法,而父类却没有定义无参构造方法,所以程序会报错。
【解决办法】:(在父类中只定义了有参构造方法,没有显示定义无参构造方法的情况下)
super注意点
this和super的不同点
重写是方法的重写,需要有继承的关系,子类重写父类的方法
重写,子类的方法和父类的方法必须一致,方法体不同
快捷键:1.alt+insert -->OverrideMethod 2.Ctrl+O
【演示】
public class Dad {
public void test() {
System.out.println("Dad-->test");
}
}
public class Son extends Dad{
@Override// 重写
public void test() {
System.out.println("Son-->test");
}
}
public class Application {
public static void main(String[] args) {
//方法的调用和左边有关,定义的数据类型有关
Son a = new Son();
a.test();
Dad b = new Son();// 父类Dad的引用b指向子类Son
b.test();// 子类的方法重写了父类的方法
}
}
执行结果:
Son-->test
Son-->test
即统一方法可以根据发送对象的不同而采取多种不同的方式
一个对象的实际类型是确定的,但是可以指向对象的引用类型有很多
多态存在的条件
多态的注意事项
static,final,private修饰的方法不能重写
【演示】
public class Person {
public void run() {
System.out.println("Person-->run");
}
}
public class Student extends Person{
@Override
public void run() {
System.out.println("Student-->run");
}
public void eat() {
System.out.println("Student-->eat");
}
}
public class Application {
public static void main(String[] args) {
/*
* 一个对象的实际类型是确定的
* new Student();
new Person();
*/
Student s1 = new Student();// student可以调用的方法都是自己的或者是父类的
Person s2 = new Student();// person父类型只能调用自己的方法,不能调用子类特有的方法
s1.run();
s1.eat();
s2.run();// 若子类重写了父类的方法,执行子类的方法
((Student)s2).eat();// 若父类型调用子类中特有的方法需要强制转换
}
}
执行结果:
Student-->run
Student-->eat
Student-->run
Student-->eat
System.out.println(X instanceof Y);能不能通过编译,看X与Y是否存在父子关系
【演示】
public class Person {
}
public class Teacher extends Person{
}
public class Student extends Person{
}
public class Application {
public static void main(String[] args) {
/*
父类----->----->---->子类
Object->String
Object->Person->Student
Object->Person->Teacher
*/
Object obj = new Student();
System.out.println(obj instanceof Object);// true
System.out.println(obj instanceof Person);// true
System.out.println(obj instanceof Student);// true
System.out.println(obj instanceof Teacher);// false
System.out.println(obj instanceof String);// false
Person per = new Student();
System.out.println(per instanceof Object);// true
System.out.println(per instanceof Person);// true
System.out.println(per instanceof Student);// true
System.out.println(per instanceof Teacher);// false
//System.out.println(per instanceof String);编译报错
Student stu = new Student();
System.out.println(stu instanceof Object);// true
System.out.println(stu instanceof Person);// true
System.out.println(stu instanceof Student);// true
//System.out.println(stu instanceof Teacher);编译报错
//System.out.println(stu instanceof String);编译报错
}
}
低(子类)转高(父类)时,由于子已经继承了父的所有,所以删去属于自己的后自然而然就可以转化为父类的;
高(父类)转低(子类)时,则需要重新开辟只属于子的空间,则需用强制转换
子类转化为父类(向上转型) 子类会丢失自己的方法
父类转化为子类(向下转型 强制转换) 可能会丢失精度或方法
public class Person {
}
public class Student extends Person{
public void eat() {
System.out.println("Student->eat");
}
}
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.eat();
Person person = student;//Student类型转为Person类型 (低转高)向上转型
//person.eat();编译报错,丢失了子类自己的方法
Person p1 = new Person();
if (p1 instanceof Student){
Student s1 = (Student) p1;//向下转型,需要强制转换
((Student) p1).eat();// 可以调用,但是不能执行,丢失了方法
}
}
}
在类中用static修饰的成员变量称为静态变量,反之则称为非静态类
静态变量与非静态变量的区别
静态变量是属于类的,“可以”使用类名.属性来访问,
非静态变量是属于对象的,“必须”使用对象来访问
public class Test {
public String name; // 非静态变量
public static int age;// 静态变量
private int id;// 非静态变量(私有的)
private static char sex;// 静态变量(私有的)
public static void main(String[] args) {
System.out.println(Test.age);// 静态变量可以使用"类名.属性"来访问
Test student = new Test();
System.out.println(student.name);// 非静态变量通过实例对象student来访问
System.out.println(student.age);// 静态变量也可通过实例对象student来访问
System.out.println(Test.sex);// 通过类名亦可访问私有静态变量
System.out.println(student.id);// 通过实例对象student亦可访问私有非静态变量
}
}
【注意】
在类中,使用static修饰的方法称为静态方法,反之则称为非静态方法。
静态方法与非静态方法的区别
注意:this和super在类中属于非静态变量(静态方法中不能使用)
public class Test02 {
public static int a;// 静态变量
public int b;// 非静态变量
public static void run() {}// 静态方法
public void go() {}// 非静态方法
/*
静态方法中不可以访问非静态变量和调用非静态方法
但是可以直接访问类中的静态变量和调用静态方法
*/
public static void statical() {
//System.out.println(b);报错
//go();报错
System.out.println(a);
run();
}
/*
非静态方法”可以”直接访问类中的非静态变量和非静态方法
也可以直接访问类中的静态变量和静态方法
*/
public void dynamic() {
System.out.println(b);
go();
System.out.println(a);
run();
}
}
为什么静态方法中不能访问非静态变量和非静态方法?
静态方法只能调用静态方法(或者变量),非静态方法可以调用静态方法(或者变量)
在一个类的静态成员中去访问其非静态成员之所以会出错是因为在类的非静态成员不存在的时候类的静态成员就已经存在了,访问一个内存中不存在的东西当然会出错。
public class Person {
public static void go() {
System.out.println("Person->go");
}
public void run() {
System.out.println("Person->run");
}
}
public class Student extends Person {
/* 子类不能重写父类的静态方法
@Override
public void go() {
super.go();
}
*/
/* 不能将父类的非静态方法重写为静态方法
@Override
public static void run() {
super.run();
}
*/
}
public class Application {
public static void main(String[] args) {
Student student = new Student();
student.go();// 子类可以继承父类的静态方法
}
}
类中可以编写代码块(匿名代码块)和静态代码块
匿名代码块和静态代码块的执行
注:每个类在第一次被使用的时候就会被加载,并且一般只加载一次
public class Test01 {
{
System.out.println("匿名代码块");
}
static {
System.out.println("静态代码块");
}
public Test01() {
System.out.println("构造方法");
}
public static void main(String[] args) {
Test01 test1 = new Test01();
Test01 test2 = new Test01();
Test01 test3 = new Test01();
}
}
执行结果:
静态代码块
匿名代码块
构造方法
匿名代码块
构造方法
匿名代码块
构造方法
匿名代码块和静态代码块的作用
public class Test02 {
public static String name;
static {
name = "张三";
}
public Test02() {
name = "李四";
}
public static void main(String[] args) {
System.out.println(Test02.name);
Test02 test = new Test02();
System.out.println(test.name);
}
}
执行结果:
张三
李四
注:在构造器中给静态变量赋值,并不能保证赋值成功,因为构造器执行是在创建对象之后才指向,但是静态变量可以不创建对象而直接使用类名来访问
Student s1 = new Student();
abstract修饰符可以用来修饰方法也可以用来修饰类,如果修饰方法,那么该方法就是抽象方法;如果用来修饰类,那么该类就是抽象类。
抽象类和抽象方法的关系:抽象类中可以没有抽象方法,但有抽象方法的类必须是抽象类!
声明类的同时,加上abstract修饰符就是抽象类
声明方法的同时,加上abstract修饰符,并且去掉方法的大括号,同时结尾加上分号,该方法就是抽象方法
public abstract class Aciton{
public abstract void doSomething();
}
public void doSomething(){...}
对于普通方法来讲:
‘public void doSomething()’这部分是方法的声明,‘{…}’是方法的实现,如果大括号里面什么都没有就是空实现
抽象类,不能使用new关键字来创建对象,它是用来让子类继承的
抽象方法,只有方法的声明,没有方法的实现,它是用来让子类实现的
子类继承抽象类后,需要实现抽象类的所有未实现的抽象方法,否则这个子类也要声明为抽象类
public abstract class Action {
public abstract void doSomething();
public void shut() {
System.out.println("shut");
}
}
public class Eat extends Action {
public void doSomething() {
System.out.println("eat");
}
}
public class Test {
public static void main(String[] args) {
//Action action = new Action();报错,抽象类不能new对象
Action eat = new Eat();
eat.doSomething();
eat.shut();
}
}
执行结果:
eat
shut
接口:只有规范(方法的声明)
接口中的方法都是抽象方法(public abstract修饰),接口的变量都是静态常量(public static final修饰)
相同点:
不同点:
【演示】
public interface UserService {
// 所有的常量默认都是public static final修饰的
int AGE = 20;
// 所有方法默认都是public abstract修饰的
void add();
void delete(String name);
}
public interface TimeService {
void timer();
}
public class UserServiceIpl implements UserService, TimeService{
/*
一个类可以实现多个接口
UserServiceIpl中需重写UserService, TimeService中所有声明的方法
*/
@Override
public void add() {
System.out.println("aaaaa");
}
@Override
public void delete(String name) {
System.out.println(name);
}
@Override
public void timer() {
System.out.println("ccccc");
}
public static void main(String[] args) {
UserServiceIpl test1 = new UserServiceIpl();
test1.add();
test1.delete("bbbbb");
test1.timer();
UserService test2 = new UserServiceIpl();
// test2只能调用UserService中声明的方法及Object中的方法
test2.add();
test2.delete("bbbbb");
TimeService test3 = new UserServiceIpl();
// test3只能调用TimeService中声明的方法及Object中的方法
test3.timer();
}
}
【扩展:一个接口继承多个接口】
public interface A {
void add();
}
public interface B {
void delete();
}
/* 接口X把接口A接口B中的方法都继承了 */
public interface X extends A, B{
void test();
}
/* Demo相当于实现了A、B、X三个接口 */
public class Demo implements X{
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void test() {
}
}
成员内部类
【演示】
public class Outer {
private int id = 110;
public void shut() {
System.out.println("这是外部类的方法");
}
public class Inner {
public void method() {
System.out.println("这是内部类的方法");
System.out.println(id);// 调用外部类中的私有变量
shut();// 调用外部类的方法
}
}
}
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.shut();
Outer.Inner inner = outer.new Inner();// 通过Outer实例化内部类Inter
inner.method();
}
}
静态内部类
【演示】
public class Outer {
private int id = 110;
public void shut() {
System.out.println("这是外部类的方法");
}
public static class Inner {
public void method() {
System.out.println("这是内部类的方法");
//System.out.println(id);报错 不能调用静态外部类中的属性
//shut();报错 不能调用静态外部类的方法
}
}
}
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.shut();
/*
Outer.Inner inner = outer.new Inner();报错
Inner是静态类类会先加载,实例化Inner时需要借助外部类,但是外部类还没有被实例化
*/
}
}
局部内部类
【演示】
public class Outer {
public void test() {
class inner {
public void method() {
System.out.println("这是局部内部类的方法");
}
}
inner inner = new inner();// 在外部类的方法中实例内部类
inner.method();
}
}
public class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.test();
}
}
执行结果:
这是局部内部类的方法
匿名内部类
【演示】
public class Demo {
public static void main(String[] args) {
new Person().run();// 实例对象没有定义名字,称为匿名
new Person().shut();
/* 匿名内部接口 */
new UserService() {
@Override
public void add() {
System.out.println("++++");
}
};
}
}
class Person {
public void run() {
System.out.println("Person->run");
}
public void shut() {
System.out.println("Person->shut");
}
}
interface UserService {
void add();
}
原文:https://www.cnblogs.com/jin99/p/14339147.html