6.面向对象

java面向对象

java的核心思想就是面向对象(object-orinented programming,OOP)

1.面向对象概念

1.1.面向过程&面向对象

  • 面向过程

    • 步骤清晰
    • 适合处理简单问题
  • 面向对象

    • 分类的思维模式,将问题分类,再对类单独思考
    • 适合处理复杂问题和多人协作问题

面向对象编程的本质就是:以类的方式组织代码,以对象的组织数据

特性:

  • 封装:将数据包装起来
  • 继承:
  • 多态:学习属于人,人分为很多,但都会执行学习,结果却不同。可以理解为同一事物的多种形态

2.回顾方法

/*修饰符 返回值类型 方法名(...){//方法体return 返回值;}
*/
public void hello(){return;
//无返回值return空就可以

2.1.break和return

break

  • 跳出switch
  • 结束循环

return

  • 结束方法

2.2.异常

public void readFile(String file) throws IOException{
}

这才是一个完整的方法命名,但是因为异常还没有提到,暂时不用抛出异常

2.3.方法调用

方法分为静态方法(static)和非静态方法

静态方法:

package method;public class method_testtwo {public static void say(){System.out.println("safas");}
}
package method;public class method_testone {//main方法public static void main(String[] args) {method_testtwo.say();}
}

非静态方法:

package method;public class method_testtwo {public void say(){System.out.println("safas");}
}
package method;public class method_testone {//main方法public static void main(String[] args) {//实例化new method_testtwo().say();}
}

一般我们也写为:

package method;public class method_testone {//main方法public static void main(String[] args) {//实例化method_testtwo test = new method_testtwo();//对象类型 对象名 = 对象值}
}

但在开发中,我们尽量用非静态方法

static是和类一起加载的,比如在一个main方法中,两个非静态变量可以相互调用,两个静态方法也可以,但一个静态一个非静态互相调用会出错(即静态调非静态错,非静态调静态错)这时候应该用new方法。目前可以这么理解,后面会详细说到。

一个类只能由一个public但可以由多个class。

package method;public class method_testone {//main方法public static void main(String[] args) {test people = new test();System.out.println(people.name);method_testone.change(people);System.out.println(people.name);}//修改class test的值,引用传递。a是一个对象,指向test这个类public static void change(test a){a.name = "阿";}}class test{String name;
}
//结果为null  阿

3.类与对象的创建

类:一种抽象的数据类型,对某一十五整体描述/定义

对象:抽象概念的具体实例

  • 使用new关键字创建对象
    • 创建时,除了分配内存空间之外,还会给创建好的对象进行默认的初始化及对类中构造器的使用
    • 类中构造器也称构造方法,是在进行创建对象时必须要调用的,并且构造器由以下两个特点
      • 必须和类的名字相同
      • 必须没有返回类型,也不能写void

3.1.类的创建

不要在每一个类中创建一个main方法,一个程序中只有一个主启动类

package method;//一个项目只存在一个main方法public class method_testone {    //一个类只有以下两个    //属性:字段 int a     //方法    int a ;//默认为0    String name;//默认为null    public void s(){        this.name = "nanana";        System.out.println(this.a+"等于");    }}//这就是一个最简单的类
package method;public class method_testtwo {    public static void main(String[] args) {        //类是抽象的,现在进行实例化        //实例化后会返回一个自己的对象        //对象就是一个method_testone类的具体实例        method_testone method_testone = new   			         }}//此为对上面代码的引用,通过类创建了一个具体

类更具体一点则是,世界上由苹果,但苹果这个类是抽象的,它是蔷薇科苹果属植物,但具体就是它有红苹果,黄苹果等。

3.2.构造器详解

构造器由以下两个特点

  • 必须和类的名字相同
  • 必须没有返回类型,也不能写void
public Person(){    }//无参构造public Persion(String name){    this.name = name;//前者是传递得到,后者为参数}//有参构造//有参构造调用package method;public class method_testone {    String name;     public method_testone(){     }     public method_testone(String name){         this.name = name;     }}//main方法package method;public class method_testtwo {    public static void main(String[] args) {        method_testone method_testone = new method_testone();        System.out.println(method_testone.name);    }}/*定义有参构造,如果要使用无参构造,必须显式的定义一个无参构造public method_testone(){     }否则会报错***当然如果new方法有参数,则直接走有参构造但无参构造必须存在,哪怕里面什么也不写*/
  • 使用new关键字必须要有构造器,本质是在调用构造器
  • 构造器一般用来初始化值
  • new方法有参数走有参构造,无参走无参构造
  • 一个文件什么都没有,默认由一个空的构造器

3.3.创建对象内存分析

更多为了理解,将在反射详细说

  1. 程序执行时,在方法区加载main方法及其属性
  2. 在栈中依次执行代码
  3. 遇见其他引(new)用则在堆中执行具体的赋值

因为先执行方法区,但方法区除了各个类(class),还有一个静态方法区,即就是static(可以知道是和类一起加载的,而且都可以直接被堆中调用的)

方法区并不区别于堆,它包含在堆里面。堆一般是具体创建的对象,而栈更多的是方法和变量的引用

3.4.总结

  1. 类是一个模板,只有属性和方法,对象是一个具体的实例

  2. 方法的定义和调用

  3. 引用类型和基本类型(8个),对象是通过引用来操作的,就是一个指向对象的地址

  4. 属性:字段Field 成员变量,且其会默认初始化

    数字:0 0.0 char:u0000 boolean:false 引用:nul

    1. 对象的创建和使用

      必须使用new关键字创建,要有构造器

      对象的属性和对象的方法都可以通过点操作符调用

      1. 类:静态的属性,动态的行为

4.封装,继承,多态

4.1.封装

封装:

public class test {    private int id;    private String name;    private char sex;    //get可以用来获得数据    public String getName(){        return this.name;    }    //set可以用来设置数据的值    public String setName(String name){        this.name = name;    }}

调用:

public class student {    public static void main(String[] args) {        test s1 = new test();        //封装之后就不可以s1.name,会报错        s1.setName("123");        //可以使用get/set方法使用        s1.getName()    }}

看起来可能没什么用,但可以在封装里进行判断,使程序更安全并保护数据。其次可以隐藏封装的细节,最后提高了可维护性。

在调用时有时用到println,这是一个方法的重载,里面会有很多。判断方式为方法名和参数列表

4.2.继承

有时候组合也可以达到和继承一样的效果

现在有两个.java文件,一个test,一个student,其中student是test的子类

子类可以继承父类的所有方法

父类:

public class test {    public  void sat(){        System.out.println("123");    }}//子类:public class student extends test{}//另一文件public class person{    public static void main(String args[]){        student s = new student();        student.say();    }}/*同样会输出父类方法,因为子类继承了父类的所有方法但是父类私有的无法继承//public公共的//protected受保护的//default默认的(可以不写)//private私有的很少有继承写除public之外的*///ctrl+h可以打开树结构,看到父类子类关系
4.2.1.object

在java中,所有类默认继承object类

4.2.2.super
System.out.println(super.name);//用于子类访问父类内容

私有的无法被继承

调用一个对象会现进行无参构造器

//调用public static void main(String args[]){    Student student = new Student();}//子类publid Student(){    System.out.println("sss");}//父类public Person(){    System.out.println("zzz");}//输出://zzz//sss

类中有构造器,但是调用一个对象会先进行无参构造器(也叫构造方法),比如public Person(){
System.out.println(“zzz”);
}

子类也有一个publid Student(){
System.out.println(“sss”);
}

调用时 默认 子类调用了父类的无参构造,并且super.调用父类构造器必须放在子类 构造器第一行

publid Student(){

​ super();

​ System.out.println(“sss”);
}

调用

  • 什么是构造器构造器通常也叫构造方法、构造函数,构造器在每个项目中几乎无处不在。当你new一个对象时,就会调用构造器。当然如果不想实例化,就用privata就可以

  • 默认构造器如果没有定义构造器,则会默认一个无参构造器,这就是为什么你定义了一个对象,比如 People,没有定义任何构造器却可以new这个对象,比如 new People() 。如果自定义了构造器,则会覆盖默认构造器。

  • 有继承的情况下的执行顺序:

  • 父类静态代码块:只在程序启动后执行一次,优先级最高

  • 子类静态代码块:只在程序启动后执行一次,优先级低于父类静态代码块

  • 父类构造代码块:父类任何一个构造器被调用的时候,都会执行一次,优先级低于子类静态代码块

  • 父类构造器:优先级低于父类构造代码

  • 子类构造代码块:子类任何一个构造器被调用的时候,都会执行一次,优先级低于父类构造器

  • 子类构造器:优先级低于子类构造代码块

  • 总结一下优先级:父类静态代码块 > 子类静态代码块 > 父类构造代码块 > 父类构造器 > 子类构造代码块 > 子类构造器

但是我们要在封装A时写上没有的无参构造,如果非要写有参不要无参,调用时应该这样

super(xxx);//这样就可以

如果不写,默认调用无参,但是你原来的文件里没有无参构造器,那么会报错

  1. super调用父类构造方法,必须在构造方法的第一个

  2. 只能出现在子类的方法或者构造方法中

  3. 和this不能同时调用构造方法,因为都要在第一行

    对比:

  4. 和this代表的对象不同,this是本身调用这的对象,super是父类对象应用

  5. this没有继承就可以用,但super只有继承了才能使用

    构造方法:

  6. this是本类构造,引用的是类的成员变量,而不是局部变量,super是父类构造

    构造器和方法区别[(5条消息) Java 基础——构造器和方法的区别_知秋一叶-CSDN博客_构造器和构造方法的区别]

4.2.3.方法的重写

方法的重写,和属性无关

只和非静态方法有关,静态方法在类一加载就已经被加载了

//子类package dome;//test子类public class student extends test {        public static void person() {            System.out.println("A=>dome.test");        }}//父类package dome;//student父类public class test {        public static void person() {                System.out.println("B=>dome.test");        }}//引用package dome;import dome.student;public class yinyong {    public static void main(String[] args) {        //父类的引用指向了子类        //但子类的引用不指向父类        //如student换成text就不行        //可以按辈分理解,儿子不能找爸爸        test B = new student();        B.person();        //方法的调用只和左边定义的数据类型有关(多态)        student A = new student();        A.person();    }}

//为什么子类不能引用父类

在super中,子类默认由super()去指向父类实例[父类引用可以指向子类对象,子类引用不能指向父类对象 - 简书 (jianshu.com)]

但我们去掉子类和父类方法的static,会出现Overrides method inXXX

//子类package dome;//test的子类public class student extends test {    //Override重写    @Override//注解:有功能的注释    public void person() {        System.out.println("A=>dome.test");    }}//父类package dome;//student的父类public class test {        public void person() {                System.out.println("B=>dome.test");        }}//引用package dome;import dome.student;public class yinyong {    public static void main(String[] args) {        //父类的引用指向了子类        //但子类的引用不指向父类        student A = new student();        A.person();        //test B = new student();//子类重写了父类的方法        //B.person();        test B = A;        B.person();    }}

和第一个代码只有子类不同,但第一个是子类父类都走了,这个两个引用都走了子类,所有:静态和非静态方法区别很大

区别

静态方法:方法的调用只和左边定义的数据类型有关

非静态方法:重写,关键词只能是public

总结:

  • 重写只是子类重写父类,也就是说有继承关系
  • 方法名和参数列表必须相同,方法体不同,否则成重载了(重载必须为当前方法)
  • 修饰符:范围可以扩大但不能缩小 private可变为public,但不能反过来
  • 抛出异常:重写可能抛出异常,但有范围,可以被缩小,但不能扩大ClassNoteFoundException --> Exception(big)

意义::父类的功能子类不一定需要,或者不一定满足

快捷键:CTRL+O

4.3.多态(方法的而不是属性的)

存在条件:

  • 继承关系
  • 子类重写父类方法
  • 父类引用指向子类对象

首先我们要知道一个对象的实际类型时确定的,比如int或者new一个对象,但根据上面我们所提到到的重写,则可以表面可以指向的引用类型是不确定的

//比如重写中我们提到的父类的引用指向子类的类型son son = new son();father father = new son();

都是son这个类型,但表现了多种引用类型,多种状态。

我们还说到object是所有类的父类

//能调用自己的和父类的son son = new son();//可以调用子类的,但不能是子类独有的方法father father = new son();Object object = new son();//也是可以的

子类重写父类方法,引用父类时,执行子类

没有重写,调用父类,执行父类

当子类出现父类没有的方法时

father.XXX();//会出错,即方法的调用只和左边定义的数据类型有关(多态)

要想调用没有的,则需要强制转换,高转低

((son)B).XXX();

1.static 属于类,不属于实例

2.final 常量

3.private 私有的

以上三种就不能重写

5.与继承有关

5.1.引用类型转换

instanceof关键字,可以判断两个类是否有父子关系

比如:

public class yinyong {    public static void main(String[] args) {        Object A = new student();        System.out.println(A instanceof student);//true        System.out.println(A instanceof Object);//true        //A是B的子类嘛    }}

同级或更小就是true

经常我们会遇见以下比较

Object>String

Object>fulei>zileei

类型转换:

父子转换

son son = new son();father father = new son();father.XXX();//会出错,即方法的调用只和左边定义的数据类型有关(多态)son son1 = (son)father;

子类转换父类不用强制,但可能丢失自己本来的一些方法

5.2.static关键字详解

static修饰的变量(方法)叫类变量(类方法)或静态变量(静态方法)

5.2.1.static的修饰限制

static的作用就是将实例成员变为类成员。static只能修饰在类里定义的成员部分,包括成员变量、方法、内部类(除局部类,因为局部类属于类本身就不再是局部类了)、初始化块、内部枚举类。如果没有使用static修饰这里类里的成员,这里成员属于该类的实例;如果使用了static修饰,这些成员就属于类本身。从这个意义上看,static只能修饰类里的成员,不能修饰外部类,不能修改局部变量、局部内部类。

5.2.2.有无static的区别

类成员变量可以分为类变量和实例变量。实例变量属于类的对象,类变量属于类。也就是说,不同对象的实例变量被分配在不同的内存空间中,而类变量对于所有的类对象共享同一个内存空间

类似于c语言结构体和共同体

实例变量和类变量::

public class testone {    int num1 = num2 + 5;    static int num2 = 20;}//num1为实例变量//num2为类变量/*你肯定会疑惑,为什么num2没有现定义就可以引用呢?但实际上num2早已经被定义了我们之前提到static修饰的东西会随着类的出现而出现看似num1先定义,其实num2先于num1*/
5.2.3.有无static的属性有什么区别

在同一个JVM(java虚拟机)内,每个类只对应一个Class对象,但每个类可以创建多个Java对象。同一个JVM内的一个类的类变量只需一块内存空间;但对于实例变量而言,该类每创建一次实例,就需要为实例变量分配一块内存空间。也就是说,程序中有几个实例,实例变量就需要几块内存空间。(可参考4.5.1.)

 class testtwo{     int name;     static int age; }//在另一程序中public class yinyong{    public static void main(String args[]){        testtwo.age = 17;//类变量初始化完成可以直接使用        testtwo q = new testtwo();//创建以一个testtwo对象        q.name = "xuesheng";        q.age = 15;//通过p修改testtwo类的类变量}
5.2.4.初始化

关于实例变量的初始化我们不说

  1. static默认初始化我们之前也说过
  2. 定义类变量时指定,比如:static int age = 17;
  3. 静态初始化块中对类变量指定初始值
class Price {    // 类成员是Price实例    final static Price INSTANCE = new Price(2.8);    // 再定义一个类变量    static double initPrice = 20;    // 定义该Price的currentPrice实例变量    double currentPrice;    public Price(double distinct) {        // 根据静态变量计算实例变量        currentPrice = initPrice - distinct;    }}public class PriceTest {    public static void main(String[] args) {        // 通过Price的INSTANCE访问currentPrice实例变量        System.out.println(Price.INSTANCE.currentPrice); // ①        // 创建Price实例        Price p = new Price(2.8);        // 通过创建的Price实例访问currentPrice实例变量        System.out.println(p.currentPrice); // ②    }}

上面程序中①、②行代码都访问Price实例的currentPrice实例变量,而且程序都是通过new Price(2.8)来创建Price实例的。表面上看,程序输出两个Price的currentPrice都应该返回17.2(由20减去2.8得到),但实际上运行程序并没有输出两个17.2,而是输出-2.8和17.2

如果仅仅停留在代码表面来看这个问题,往往很难得到正确的结果,下面从内存角度来分析这个程序。第一次用到Price类时,程序开始对Price类进行初始化,初始化分成以下2个阶段。

(1)系统为Price的两个类变量分配内存空间。
(2)按初始化代码(定义时指定初始化值和初始化块中执行初始值)的排列顺序对类变量执行初始化。
初始化第一阶段,系统先为INSTANCE、initPrice两个类变量分配内存空间,此时INSTANCE、initPrice的默认值null和0.0。截止初始化进入第二个阶段,程序按顺序依次为INSTANCE、initPrice进行复制。对INSTANCE赋值时要调用Price(2.8),创建Price实例,此时立即执行程序中③代码为currentPrice进行赋值,此时initPrice类变量的值为0,因此赋值的结果是currentPrice等于-2.8。接着,程序再次将initPrice赋为20,但此时对INSTANCE的currentPrice实例变量以及不起作用了。

当Price类初始化完成后,INSTANCE类变量引用到一个currentPrice为-2.8的Price实例,而initPrice类变量的值为20.0。当再次创建Price实例时,该Price实例的currentPrice实例变量的值才等于20.0
————————————————
版权声明:本文为CSDN博主「麦田」的原创文章,遵循CC 4.0 BY-SA版权协议。
原文链接:https://blog.csdn.net/itmyhome1990/article/details/77833010

5.3.抽象类

是一种特殊的类,不能创建对象,只能由其派生子类创建。

抽象类是专门作为其他类的父类来使用的。

原因:

​ 在编写程序时,经常创造父类及其一系列子类,这时会将其中有特性的抽取出来,创建包含这些共有特性的抽象类,并由此派生出更具体,更多实现的后代类,形成一个完整的类的层次体系。

5.3.1.抽象类定义

用abstract关键字

public abstract class test{    //类体}//orabstract public testone{    //类体}//orabstract class testtwo{    //类体}
5.3.2.抽象方法定义
abstract returnType methodName()//retuenType为方法返回的类型,methodName为方法名abstract protected float run()    //orprotected abstract float run()
5.3.3.实例
//fatherabstract class Animal{    //声明被所有子类共享的成员变量    String name;    ...    //声明已经实现的成员方法,可以被所有子类共享    void sleep() {        ...    }    //声明抽象方法,由各个子类去具体实现    abstract void run();    abstract void eat();}//sonclass dog extands Animal{    void run(){        ...    }    void eat(){        ...    }}class bird extands Animal{    void run(){        ...    }    void eat(){        ...    }}

5.4.接口

Java中一个类只能有一个父类,这种单继承使得java更简单,为了实现多继承,我们使用接口来实现。关键字为:interface

5.4.1.接口的定义
interface interName{    //接口体中的变量和方法}

在java接口中,所有的方法都是***抽象的方法***,所有的变量都是***static常量***

实例:

interface animal{	static final int max = 100;//int类型变量max    int min = 20;//int类型变量min,编译器自动加上static final    abstract void run();//抽象类方法run    float sum(float x,float y);//抽象类方法sum}
5.4.2.接口的使用

一个类通过关键字implements声明自己使用一个或多个接口,多个接口逗号隔开

class run impelments family1,family2,...

注意:

  • 接口中的方法是抽象方法,故实现它的类必须实现接口中的所有方法
  • 实现方法时,必须要public修饰,因为接口方法默认public
  • 返回类型不是void时,要用return
  • 声明接口时,如果interface有public关键字,则此接口可以被任何一个类使用。不加public,称为友好接口,可以被同一个包中的所有类使用
5.4.3.接口的继承
interface run{    public void method1();}interface run2 extands run{    public void method2();}public class init implements run,run2{	public void method1(){        ...    }    public void method2(){        ...    }}

5.5.内部类

所有内部类都在一个类中

5.5.1.匿名类

指将类的定义和类的对象合并在一起的情况

//定义接口interface testone{	public void methodone();}//定义类实现接口class achieve{    public static void main(String args[]){        //接口对象obj生成的同时就定义了匿名类,并实现了方法        test obj = new test(){            //匿名类开始            public void methodone(){                System.out.println("匿名类中实现接口的方法");            }            //匿名类结束            obj.methodone();        }    }}
5.5.2.匿名类意义

有的时候, 为一个功能或者实例化一个对象, 需要实现一个接口, 但是接口应用的地方很多, 但是每个地方的实现都不尽相同, 而且需要实例化的地方就只只有那么一两处, 这个时候, 如果为了这些地方, 每声明一个类来实现接口的话, 就会浪费很多空间, 匿名内部类可以在需要的地方使用接口, 可以在使用的同时实现, 这样就节省了空间,

5.5.3.静态类

作为静态成员存在于某个类中,加入static即可

class test{	static class run{            }}

创建静态类对象的两种情况:

  • 在test内部,创建run对象

    run obj = new run();
    
  • 在test外部,创建run对象

    test.run obj = new test.run();
    
5.5.4.静态类意义

只有嵌套的类才有可能成为静态类,这样可以避免使用其外部类。静态类内部方法为静态方法

5.5.5.成员类

作为一般的成员变量存在于某个类中

class test{    class memberName{            }}//对象创建和静态类一样
5.5.6.成员类意义
5.5.7.局部类
class test{    void method(){        class inName{            ...        }    }}
5.5.8.局部类意义

方法method执行完毕,类inName就会消失


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部