面向对象编程
- java的核心思想oop
初识面向对象
- 面向过程思想
- 步骤清晰简单,第一步做什么,第二步做什么……
- 面向过程适合处理一些较为简单的问题
- 面向对象思想
- 物以类聚,分类的思维模式,思考问题首先思考要解决的问题有哪些分类,然后对这些分类进行单独思考。最后,在对某个分类下的细节进行面向过程的思索。
- 面向对象适合复杂的问题,适合处理需要多人协作的问题
- 对于描述复杂的事物,为了从宏观上把握、从整体上分析,我们需要使用面向对象思路来分析整个系统。但是,到微观操作,任然需要面向过程的的思路处理。
- 面向过程编程的本质:以类的方式组织代码,以对象的方式组织(封装)数据
- 抽象
- 三大特性
- 封装
- 继承
- 多态
- 从认识的角度考虑,先有对象后有类。对象是具体的事物,类是抽象的,是对类的抽象
- 从代码的运行角度考虑先有类后有对象,类是对象的模板
回顾方法的定义
-
方法的定义
-
修饰符
含有static为静态,否则为非静态。静态可以直接调用,非静态需要定义使用
-
返回值类型
可以有返回值也可以没有,数组也可以是返回值
-
break,跳出switch、结束循环。return,代表方法结束
-
方法名
注意规范(驼峰原则),见名知意
-
参数列表
参数类型,参数名(可变长参数,需要放在最后)
-
异常的抛出
-
-
方法的调用-----(递归)
-
静态方法
有static,使用时、类名.方法名、就可以使用,自己可以调用自己,但不能与非静态混调
-
非静态方法
无static,使用时需要先进性new一个对象,在使用,自己可以调用自己,但不能与静态混调
-
形参和实参
方法中传入的参数,表明需要接收什么类型的值,要接收多少,太多同类型的,或同类型不知道有多少个数的,可以使用可变长参数,但一个方法只能有一个,而且需要放在最后
-
值传递和引用传递
java只有值传递,引用传递 给对象,本质是值传递。值传递不改变原值,引用传递直接在原值上改动。
-
this关键字
-
类与对象的关系
- 类是一个抽象的数据类型,它是对某一事物的整体描述、定义,但不能代表某一具体事物
- 对象是抽象概念的具体事例
创建与初始化对象
- 使用new关键字
- 使用new关键字创建时,除了分配内存空间之外。还会给创建好的对象进行默认的初始化及对类中构造器的调用
- 类中的构造器也称为构造方法,是在进行创建对象时必须调用的。构造器有以下两个特点
- 必须和类名相同
- 必须没有返回类型,也不能写void
package oop.demo02;
//一个项目只存在一个main方法
public class Application {
public static void main(String[] args) {
//把类实例化为一个对象
//类是抽象的,需要实例化
//类实例化后,会返回一个自己的对象
//studentd对象是Student类的一个具体实例
Student agaio = new Student();
Student laoba = new Student();
agaio.name="小阿giao";
agaio.age=3;
System.out.println(agaio.name);
System.out.println(agaio.age+"岁");
agaio.agiao();
System.out.println("==============================");
laoba.name="老八";
laoba.age=4;
System.out.println(laoba.name);
System.out.println(laoba.age+"岁");
laoba.laoba();
}
}
package oop.demo02;
public class Student {
//属性 字段
String name;
int age;
//方法
public void agiao(){
System.out.println(this.name+"------>一给我的giao");
}
public void laoba(){
System.out.println(this.name+"------>只有你们想不到的,没有我老八做不到的");
}
}
/*
结果
小阿giao
3
小阿giao------>一给我的giao
==============================
老八
4
老八------>只有你们想不到的,没有我老八做不到的
Process finished with exit code 0
*/
构造器详解
- 构造器必须理解
- 和类名相同没有返回值
- 作用,new的本质是在调用构造方法,还可以初始化值
- 定义构造器后,如果想使用无参构造器,必须显示定义一个无参构造
- 即使你的方法里什么都没写,但是会自动生成一个无参构造器
- 生成构造器快捷键Alt+Insert
package oop.demo02;
//java------------>class、、、、out文件夹查看
public class Person {
//即使一个类里,什么都没写也会存在一个方法,看class文件
//显示的定义构造器
//可以给实例化对象一些初始值
String name;
//使用new关键字,必须要有构造器
//构造器一般用来初始化值
public Person(){
//this.name="小阿giao";
}
//有参构造,一旦定义了有参构造,就必须写无参构造
public Person(String name){
this.name=name;
}
//方法重载
//alt+insert-------------》自动生成构造器
}
/*
public static void main(String[] args) {
//mew一个实例化的对象
Person person = new Person("小阿giao");
System.out.println(person.name);
}
*/
创建对象内存分析
package oop.demo03;
public class Pet {
public String name;
public int age;
public void shout(){
System.out.println(this.name+"叫了一声");
}
}
/*
public static void main(String[] args) {
Pet dog = new Pet();
Pet cat = new Pet();
dog.name="123";
cat.name="456";
}
*/
对象小结
-
类与对象
类是一个模板是抽象的,是一种有相似框架的事物的框架。对象是具体的实例(实物)
-
方法
定义、调用
-
对象的引用
引用类型,基本类型(8种)
对象是通过引用来操作的,栈--------->堆
-
属性,字段field 成员变量
默认初始化
整数 0 0.0
char u0000
boolean false
引用类型 null
-
对象的创建和使用
必须使用new关键字,创建对象,无参构造器
对象的属性 dog.name
对象的方法 dog.shout()
-
类
静态的属性 属性
动态的行为 方法
封装
- 该露的露,该藏的藏
- 我们的程序设计要追求,“高内聚,低耦合”。高内聚是类的内部操作细节自己完成,不允许外部干涉。低耦合,仅暴露少量方法供外部使用
- 数据的隐藏(封装)
- 通常,应禁止直接访问一个对象中数据的实际表示,而应通过操作接口来访问,这称为信息隐藏
- 记住这句话,属性私有、get、set
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统的可维护性增加
package oop.demo04;
public class Student {
//属性 私有
private String name;//姓名
private int id;//学号
private char sex;//性别
private int age;
//提供一些可以操作这些类的方法
//提供一些pubilc 的 set get 方法
//get 获取这些数据
public String getName() {
return this.name;
}
//set 给这个数据设置数据
public void setName(String name){
this.name=name;
}
//Alt+Insert
public int getAge() {
return age;
}
public void setAge(int age) {
if(0<=age&&age<=120) {
this.age = id;
}else{
this.age=3;
}
}
}
/*
//提高程序的安全性,保护数据
//隐藏代码的实现细节
//统一接口
//系统的可维护性增加
public static void main(String[] args) {
Student s1 = new Student();
s1.setName("小阿gaio");
System.out.println(s1.getName());
s1.setAge(9999);
System.out.println(s1.getAge());
}
*/
继承
- 继承的本质是对某一批类的抽象,从而实现对现实世界的建模
- extends的意思“扩展”,子类是父类的扩展
- java中类只有单继承,没有多继承。一个儿子只能有一个爸爸,一个爸爸有横多儿子。
- 继承是类与类之间的一种关系。除此之外,类和类之间的关系还有依赖、组合、聚合等。
- 继承关系的两个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
- 子类和父类之间的关系,从意义上讲有“is a”的关系
package oop;
import oop.demo05.Student;
//一个项目只存在一个main方法
public abstract class Application {
public static void main(String[] args) {
Student s1 = new Student();
s1.say();
}
}
/*
package oop.demo05;
//在java中所有的类都默认直接或间接继承object类
//人 父类
public class Person {
public int moneg;
public void say(){
System.out.println("一给我的giao");
}
public int getMoneg() {
return moneg;
}
public void setMoneg(int moneg) {
this.moneg = moneg;
}
}
package oop.demo05;
//老师 派生类 子类
public class Tacher extends Person{
}
package oop.demo05;
//学生 派生类 子类
//子类继承了父类,就会拥有父类的全部方法
//Ctrl+h 打开继承树
public class Student extends Person{
}
*/
Super详解
- 私有的东西,无法被继承
- 调用子类的无参构造,父类的会先与子类无参构造之前被调用,相当于在子类的代码前加了一句,super();
- super();若要显示的写出来,那么必须在子类构造器的第一行
- 注意点
- super调用父类方法,必须在构造方法的第一行
- super只能出现在子类的方法或构造方法之中
- super和this不能同时调用构造方法
- 与this比较
- this表示调用者这个对象
- super代表父类对象的引用
- this在没有继承是也可以使用
- super只能在继承条件下使用
- this默认调用本类的构造方法
- super,调用父类的构造
方法重写
-
前提需要有继承关系,子类重写父类的方法
-
重写是方法的重写,与属性无关
-
父类的引用指向了子类
-
静态方法的调用之和左边有关,定义了数据类型有关
-
非静态方法才算重写
-
@override重写的注解(有功能的注释)
-
重写的关键词只能是public
-
子类的方法与父类的一致,方法体不同
-
快捷键,Alt+Insert选择override
- 方法名必须相同
- 参数列表必须相同(没有继承关系,重载)
- 修饰符,范围可以扩大,但不能缩小,public>protected>default>private
- 抛出的异常可以被缩小但不能扩大
为什么需要重写
- 父类的功能子类不一定需要,或者不一定满足
多态
-
类型,动态编译,可扩展性更强
-
即同一方法可以可以根据发送对象的不同而采用不同的行为方式
-
一个类的实际类型是确定的,但可以指向的对象的引用类型有很多
-
多态存在的条件
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类对象
-
注意,多态是方法的多态,属性没有多态
-
instanceof
-
子类重写了父类的方法,则执行子类中的方法
-
注意事项
-
多态是方法的多态,属性没有多态
-
父类和子类,有联系,ClassCastException(类型转换异常)
-
多态存在的条件,继承关系,方法重写,父类对象指向子类,Father f1=new Son();
-
static方法属于类,不属于实例不能重写
-
final,常量不能重重写
-
private方法也不能重写
-
package oop;
import oop.demo06.Person;
import oop.demo06.Student;
//一个项目只存在一个main方法
public abstract class Application {
public static void main(String[] args) {
//父类引用指向子类,引用类型不确定
//对象能执行哪些方法,主要看对象左边的类型,和左边关系不大
//Student能调用的方法,都是自己的或者继承父类的
Student s1 = new Student();
//Person父类型,可以指向子类,但是不能调用子类独有的方法
Person s2 = new Student();
Object s3 = new Student();
s2.run();//子类重写了父类的方法,则执行子类中的方法
s1.run();
//((Student) s2).eat(); 强制转换
}
}
/*
package oop.demo06;
public class Student extends Person {
@Override
public void run() {
System.out.println("son");
}
public void eat(){
System.out.println("eat");
}
}
package oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
*/
instanceof和类型转换(引用类型判断一个对象是什么类型)
- 父类的引用指向子类的对象
- 把子类转换为父类,向上转型,不用强制转换,自动就可以转换
- 把父类转换为子类,向下转型,用强制转换,可能会丢失一些方法
- 方便方法的调用,减少重复的代码
package oop;
import oop.demo06.Person;
import oop.demo06.Student;
import oop.demo06.Teacher;
public abstract class Application {
public static void main(String[] args) {
//父类转化为子类需要强转,子类转化为父类自动转化
//
Student s1 = new Student();
s1.go();
System.out.println("========================================");
//Student将这个对象转换为Student,就能使用Student方法了
Person obj = new Student();
Student s2=(Student)obj;
s2.go();
//以上简短写法
//((Student)obj).go();
System.out.println("========================================");
//把Student变成Person类型,person类型不能使用go()方法
//因此可知当进行低转高时会出现方法不能使用的现象
//子类转换为父类可能会失去一些自己的方法
Person s3= s1;
}
}
/*
Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false
System.out.println("========================================");
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Teacher);//false
//System.out.println(person instanceof String);//编译报错
System.out.println("========================================");
package oop.demo06;
public class Student extends Person {
public void go(){
System.out.println("go");
}
}
package oop.demo06;
public class Teacher extends Person{
}
package oop.demo06;
public class Person {
public void run(){
System.out.println("run");
}
}
*/
static关键字
package oop.demo07;
//import java.lang.Math; 使用后可以直接调用Math类中的方法
//System.out.println(random());//随机数产生
//import static java.lang.Math.random; 静态导入包
//被final修饰不能被继承
public class Test {
public static void main(String[] args) {
System.out.println(Math.random());//随机数产生
}
}
package oop.demo07;
public class Person {
{
//第2执行,与对象同时产生,可用于赋初始值
//代码块(匿名代码块)
System.out.println("匿名代码块");
}
static{
//第1执行,且只执行一次
//静态代码块
System.out.println("静态代码块");
}
public Person(){
//第3执行
System.out.println("构造方法");
}
public static void main(String[] args) {
Person person1 = new Person();
System.out.println("=================");
Person person2 = new Person();//输出时静态代码块没有了
}
}
package oop.demo07;
public class Student {
//static 用在类就是,静态类,用在方法就是静态方法
private static int age=1; //静态变量 多线程
private double score=0.1; //非静态变量
public static void run(){
}
public static void go(){
}
public static void main(String[] args) {
/*
Student s1 = new Student();
System.out.println(Student.age);
System.out.println(s1.age);
System.out.println("====================");
// System.out.println(Student.score);报错
System.out.println(s1.score);
*/
Student student = new Student();
student.go();
//上面的简写,new Student().go();
Student.run();
//静态方法可以调用静态方法
run();
}
}
抽象类
- abstract修饰符可以用来修饰方法也可以用来修饰类。如果修饰方法,那么该方法是抽象方法。如果修饰类,那么该方法是抽象类。
- 抽象类中可以没有抽象方法,但是有抽象方法的类一定要申明为抽象类
- 抽象类,不能使用new关键字来创建对象,它是用来让子类继承的
- 抽象方法,只有方法的申明,没有方法的实现,他是让子类来实现的
- 子类继承抽象类,那么就必须要实现抽象类没有实现的抽象方法,否则该子类也要申明为抽象类
package oop.demo08;
//abstract抽象类
public abstract class Action {
//约束----有人帮你实现
//抽象abstract方法,只有方法的名字,没有方法的实现,无方法体
public abstract void doSomething();
}
/*
package oop.demo08;
//抽象类的所有方法,继承他的子类,都必须要实现他的方法,除非子类也是抽象类,那就有子子类实现
//extends 单继承
//接口 多继承
public class A extends Action{
@Override
public void doSomething() {
}
//抽象的抽象,约束
//不能new抽象类,只能让子类去实现它
//抽象方法必须在抽象类中
//抽象类里可以写普通方法
public void go(){
System.out.println("");
}
}
//思考
//抽象类不能new,存在构造器吗
//抽象类存在的意义
*/
-
抽象类不能new,存在构造器吗
有构造器
-
抽象类存在的意义
- 例如,兔子,老鼠,都是哺乳动物,可以用抽象类来规定他们的相同点(属性)哺乳等
- 现在要加入西安的哺乳动物人,直接继承哺乳动物类就好了,再添加自己特有的方法即可
- 还是不太懂------------------------------------
接口
- 对比
- 普通类,只有具体实现
- 抽象类,具体实现和规范(抽象方法)都有
- 接口只有规范,约束和实现分离
- 接口就是规范,定义了一些规则,体现了现实世界中,“如果你是……则必有……”的意思,例,如果你是哺乳动物,则必有你需要喝奶
- 接口本质是契约,就像人类的法律,制定好后就必须遵守
- 面向对象的精髓,就是对对象的抽象,最能体现这一点的就是接口,为什么我们讨论设计模式都是讨论具备抽象能力的语言(c++、java、C#等),就是因为设计模式所研究的就是如何合理的去抽象
- 声明接口的关键字,interface
- 作用
- java的接口是约束
- 定义一些方法,让不同的类实现
- public abstract,定义方法是默认的修饰
- public static final,定义常量的默认修饰(一般不在接口里写)
- 接口不能被实例化,没有构造方法
- implements可以实现多个接口的方法的实现,必须要实现接口中的方法(否则报错)
package oop.demo09;
//定义的关键字interf
//接口都需要有实现类
public interface UserServi {
//接口中的所有定义都是抽象的 public
//public abstract显示灰色,可以不写
//public abstract void run();
//接口中常量的修饰为,public static final
int AGE=99; //常量的定义,用大写
void add(String name);
void delete(String name);
void uodate(String name);
void query(String name);
}
/*
package oop.demo09;
public interface TimeService {
void timer();
}
package oop.demo09;
//类可以实现接口,用,implements
//实现接口的类,就必须重写接口的方法
//利用借口来实现,多继承
public class UserServImpl implements UserServi,TimeService{
@Override
public void add(String name) {
}
@Override
public void delete(String name) {
}
@Override
public void uodate(String name) {
}
@Override
public void query(String name) {
}
@Override
public void timer() {
}
}
*/
内部类
package oop;
import oop.demo10.Outer;
public abstract class Application {
public static void main(String[] args) {
Outer outer = new Outer();
outer.out();
System.out.println("========================");
//内部类通过外部类来实例化
//对象的类型叫 Outer.Inner
Outer.Inner inner = outer.new Inner();
inner.in();
System.out.println("========================");
inner.getId();
}
}
/*
package oop.demo10;
public class Outer {
}
//一个java文件中只能有一个public类,但可以有多各类
class a{
}
/*
package oop.demo10;
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);
}
}
}
*/
*/
/*
package oop.demo10;
import oop.demo08.A;
public class Test {
public static void main(String[] args) {
//没有名字初始化类,不用将实例保存到变量中
new Apple().eat();
new UserService(){
@Override
public void hello() {
}
};
}
}
class Apple{
public void eat(){
System.out.println("eat");
}
}
interface UserService{
void hello();
}
*/