1.概念
面向对象本质是一种编程范式(一种思考方式)
面向过程:关注的是代码的实现细节
面向对象:先把代码实现细节整合到对象中,找到这个对象就能拥有对象的功能
面向对象基于面向过程,面向对象优于面向过程?如果场景比较简单优先推荐面向过程,如果场景很复杂优先推荐面向对象
2.对象和类之间的关系
对一类对象来进行抽取,把共有的特征信息抽取成了属性,把共有的行为信息抽取成了方法,把这一类对象抽取成了类。类是对对象的概括,对象是对类的具体实现。
3.构造方法
a.构建对象
b.1.与类同名 2.没有返回值类型
c.有参构造用于属性初始化,支持构造方法重载
d.当类中没有定义任何形式的构造方法JVM会在底层默认添加无参构造,如果类中已经定义构造方法那么底层就不会再添加无参构造
e.类中至少含有一个构造方法
//当类中没有定义任何形式的构造方法JVM默认在底层会添加无参构造
//当类中定义构造方法底层就不会默认添加无参构造
//无参构造
//1.没有返回值类型2.与类同名
//public Person(){}
//普通方法可以与类同名
//public void Person(){}
//有参构造---对象属性初始化
//java支持构造方法重载
public Person(Stringname){//方法有就近原则
//this代表当前类的对象
this.name=name;
}
注意:java中所有的非静态属性和方法要由对象调用
4.this
a.关键字,代表当前类的对象
b.可以代表当前类还没有产生的对象,代表当前类刚创建的对象,代表当前类正在使用的对象。this是灵活的指代(虚拟),可以指代成当前类正在活动的对象。
c.this语句—在同一个类中的构造方法里调用别的构造方法,首行
package cn.tedu.object;
public classThisDemo{
public static void main(String[]args){
//创建对象
Student s1=new Student();
//this可以代表当前类刚创建对象
System.out.println("s1:"+s1);
//创建对象
Student s2=new Student("tom");
//this是一个灵活的指代
System.out.println("s2:"+s2);
//this指代成当前类正在使用的对象
s1.study();
}
}
//代表学生的类
class Student{
//属性
String name;
int age;
char gender;
//无参构造
public Student(){
System.out.println("this:"+this);
}
//有参构造
public Student(intage){
this();
}
public Student(Stringname){
//调用别的构造方法
//Student();调用不到
//this语句---调用别的构造方法要在首行
this(1);
this.name=name;
System.out.println("this:"+this);
}
//方法
public void study(){
//this可以代表当前类好没有创建对象
System.out.println(this.name+"在学习...");
//
System.out.println("this:"+this);
}
}
5.构造代码块
a.在方法外类内{}
b.属性初始化
c.优先于所有的构造方法先执行
package cn.tedu.object;
public class ObjectDemo2{
public static void main(String[]args){
//
Baby b=new Baby();
//
System.out.println(b.name+","+b.age);
}
}
//代表婴儿的类--创建对象就是真实的婴儿
//要求:不管怎么出生,婴儿的名字都叫莉莉,年龄是1岁
class Baby{
//属性
String name;
int age;
char gender;
//构造代码块
//优先于所有的构造方法先执行
//属性初始化
{
this.name="莉莉";
this.age=1;
}
//无参构造---婴儿没有名字没有年龄
public Baby(){
/*this.name="莉莉";
this.age=1;*/
}
//有参构造---婴儿出生时有名字
public Baby(String name){
//this.name=name;
/*this.name="莉莉";
this.age=1;*/
}
//婴儿出生时有名字也有年龄
public Baby(String name,int age){
/*this.name=name;
this.age=age;*/
/*this.name="莉莉";
this.age=1;*/
}
//方法
public void cry(){
System.out.println(name+"在嗷嗷的哭...");
}
}
6.局部代码块
a.在方法内{}
b.控制变量的生命周期,提供内存利用率
package cn.tedu.object;
public class ObjectDemo3{
public static void main(String[]args){
int x=1;
//局部(方法)代码块,控制变量的生命周期
{
int y=2;
System.out.println(x+y);
}
//1000行代码没有使用上面定义变量
}
}
7.成员变量与局部变量的区别
1.位置
成员变量:方法外类内
局部变量:方法内
2.使用范围
成员变量:整个类
局部变量:整个方法
3.内存
成员变量:堆
局部变量:栈
4.生命周期
成员变量:随着类创建对象而出现,随着对象被回收而消失
局部变量:当方法被调用时才出现随着方法执行结束而消失
面向对象的特征
封装、继承、多态(抽象)
体现形式—方法,属性私有化并且提供公共的访问方式来进行正常取值和赋值,提高代码数据安全性。
package cn.tedu.fengzhuang;
public class FZDemo{
public static void main(String[]args){
//创建代表人的类的对象
Person p=new Person();
//给对象属性赋值
//p.name="豆豆";
//调用方法间接给私有化属性进行赋值
p.setAge(-10);
//p.gender='男';
//调用方法间接给私有化属性进行取值
//System.out.println(p.name+","+p.getAge()+","+p.gender);
}
}
//代表人的类
class Person{
//属性
private String name;
//私有化属性,只能在本类中直接使用
private int age;
private char gender;
//Alt+Insert---Generate---GetterandSetter
//java自动提供
public String getName(){
return name;
}
public void setName(Stringname){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(intage){
this.age=age;
}
public char getGender(){
return gender;
}
public void setGender(chargender){
this.gender=gender;
}
/*//定义方法间接的给私有化属性进行赋值
public void setAge(intage){
if(age<0){
System.out.println("数据有误!!!");
}else{
this.age=age;
}
}
//定义方法间接的给私有化属性进行取值
public int getAge(){
return age;
}*/
/*//有参构造
public Person(intage){
if(age<0){
System.out.println("数据有误!!!");
}else{
this.age=age;
}
}*/
}
继承
概念
如果多个类的内容出现重复,把重复的内容放到一个新的类中,通过extends关键字让原来的类和新的类产生关联关系—继承。原来的类是子类,新的类是父类。子类可以继承父类部分信息(父类的私有化信息、构造方法以及构造代码块不能被继承)。
packagecn.tedu.extendsx;
public class ExtendsDemo1{
public static void main(String[]args){
//创建子类对象---医生类对象
Doctor d=new Doctor();
d.treat();
}
}
//定义医疗人员类
//基类、超类、父类
class医疗人员{
//属性
String name;
int age;
char gender;
//科室
String dept;
//方法
public void treat(){
System.out.println(name+"在治病救人...");
}
}
//定义代表医生的类
//通过extends关键字让两个类之间产生关联关系----继承
//派生类、子类
class Doctor extends 医疗人员{
public void treat(){
System.out.println(name+"拿着手术刀在治病救人...");
}
}
//代表护士的类
class Nurse extends 医疗人员{
}
继承方式(单继承)
子类只能有一个父类,一个父类可以有多个子类
Class A extends B{} class B extends C{} class C{}(多级继承)
重写(覆盖)
在父子类中出现方法签名一致的方法称之为重写 遵守重写原则(两等两小一大)
方法签名一致(前提)
当父类方法返回值类型是基本类型/void时那么子类方法返回值类型要和父类方法返回值类型保持一致
class A{
public int m(){return 1;}
}
class B extends A{
public int m(){return 2;}
}
当父类方法返回值类型是引用类型时,那么子类方法返回值类型要么和父类方法返回值类型一致要么是父类方法返回值类型的子类
class A{}
class B extends A{}
class C{
public A m(){return null;}
}
class D extends C{
public A/B m(){return null;}
}
子类方法访问权限修饰符要么和父类方法访问权限修饰符范围一致要么比父类方法访问权限修饰符的范围要大
class A{
void m(){}
}
class B extends A{
public void m(){}
}
访问权限修饰符—控制在哪个位置关系(定义信息地方和获取信息的地方产生四种位置关系—本类、同包类、其他类、子类)下可以获取定义的信息
super
a.关键字,代表父类对象
b.super语句—在子类构造方法里调用父类构造方法 首行使用
c.每个子类构造方法里默认调用父类无参构造,如果父类没有提供无参构造需要每个子类构造方法里手写super有参调用对应的父类有参构造
d.父类对象优先于子类对象先出现
e.父子类执行顺序(对象级别)—父类构造代码块-父类构造方法-子类构造代码块-子类构造方法
package cn.tedu.extendsx;
publi cclass Extends Demo3{
public static void main(String[]args){
//创建子类对象
Pig p=new Pig(1);
//p.eat();
}
}
//定义代表动物的类
class Animal{
//父类构造方法
/*public Animal(){
System.out.println("父类无参构造");
}*/
public Animal(String s){
}
public void eat(){
System.out.println("在吃东西...");
}
public void sleep(){
System.out.println("在睡觉...");
}
}
//定义代表猪的类
class Pig extends Animal{
//父类对象优先于子类对象先出现
//子类无参光构造
//子类所有的构造方法中都有默认调用父类的无参构造
//如果父类没有提供无参构造,每个子类构造方法都要手写super有参语句调用父类有参构造
public Pig(){
//super语句---调用父类构造方法,要在首行
super("sd");
System.out.println("子类无参构造");
}
public Pig(inti){
//
super("123");
System.out.println("子类有参构造");
}
//重写eat方法
public void eat(){
System.out.println("在无忧无虑的吃东西。。。");
System.out.println("吃着吃着吃饱了。。。想睡觉。。。");
//java中所有的非静态方法与属性都需要通过对象调用
//this?代表当前类的对象
//super代表父类"对象"可以调用父类里的信息
super.sleep();
}
}
多态
概念
代码执行过程中呈现的多种形式
java分为编译时期、运行时期
编译时多态—在编译时期绑定代码 体现形式—重载
public void m(){…}
public void m(int i){…}
运行时多态—在运行时期绑定代码 体现形式—重写、向上造型(继承)
向上造型
可以调用哪些方法看父类,方法的具体执行看子类(父类—目录 子类—正文)
package cn.tedu.duotai;
public class DTDemo{
public static void main(String[]args){
/*//养个宠物
Pet p;
//养的宠物就是一条狗
p=new Dog();*/
//左边声明类是父类,右边实际创建类是子类---向上造型
Pet p=new Dog();
//向上造型对象可以调用哪些方法看父类
//方法的具体执行要看子类是否有重写方法
p.eat();
//调用方法
//匿名对象是当做参数来传递
m(new Pet());
m(new Dog());
m(new Cat());
}
//可以接收本类对象以及所有的子类对象
public static void m(Pet p){//=new Pet();=new Dog();=new Cat();
p.eat();
}
}
//定义代表宠物的类
class Pet{
public void eat(){
System.out.println("在吃东西。。。");
}
public void sleep(){
System.out.println("在睡觉。。。");
}
}
//定义代表狗的类
class Dog extends Pet{
//重写eat方法
public void eat(){
System.out.println("在呼哧呼哧的吃。。。");
}
public void brak(){
System.out.println("在汪汪汪的叫。。。");
}
}
//定义代表猫的类
class Cat extends Pet{
//重写eat方法
public void eat(){
System.out.println("在呼哧呼哧的吃。。。");
}
public void 磨爪子(){
System.out.println("在哼哧哼哧的磨爪子。。。");
}
}
解释重写原则(反证法)
1.子类方法访问权限修饰符要么和父类方法访问权限修饰符范围一致要么大于父类的方法访问权限修饰符的范围
class A{
public void m(){}
}
class B extends A{
void m(){}
}
A a=new B();//向上造型,声明类是A类可以调用A类里m方法,表面这个m方法可以在任意位置被调用。
a.m();//向上造型对象调用方法具体执行看子类是否有重写方法,执行B类里的m方法,表面m方法同包范围内被调用。此时前后有矛盾,代码错误的
2.当父类方法返回值类型是引用类型时,那么子类方法返回值类型要么和父类方法返回值类型一致要么是父类方法返回值类型的子类
class A{
}
class B extends A{}
class C{
public B m(){return null;}
}
class D extends C{
public A m(){return null;}
}
C c=new D();//向上造型对象c,调用声明类C类m方法返回B类对象可以获取B类里信息。
A a=c.m();//向上造型执行具体方法看子类D类,调用D类里m方法返回A类对象a,由a对象可以获取A类里信息。此时前后矛盾,证明代码是错误的
多态优点
1.统一参数类型
2.降低耦合度(高内聚、低耦合)