毕向东Java基础教程-面向对象

面向对象的概念

举例:大象装进冰箱。

  1. 面向过程
    步骤:打开冰箱--存储大象--关上冰箱。对于面向过程思想,强调的是过程(动作)。
    代表语言:C语言

  2. 面向对象
    步骤:冰箱打开--冰箱存储--冰箱关闭(只用找到冰箱即可)。对于面向对象思想,强调的是对象(实体)。
    特点:
    1、面向对象是一种常见的思想,符合人们的思考习惯
    2、面向对象的出现,将复杂的问题简单化(放在生活中,即是特定的事交给特定的人做)

  • 面向对象让曾经在过程中的执行者,变成了对象中的指挥者
    特征:封装、继承、多态(如果未体现这三个特征,就不能说运用了面向对象的思想 )
    代表语言:C++,Java,C#

举例:人开门
两个对象:人和门(名词体现法),开门的方法应该写在门中(门最清楚打开门这个动作)。

类与对象的关系

:用Java语言对现实生活中的事物进行描述,通常只关注属性和行为这两方面。定义类其实就是在定义类中的成员——成员:成员变量<-->属性,成员函数<-->行为。
对象:该类事物的实例,在Java中通过new关键字来创建的。对象的出现,是为了封装数据(类的每个实例,都有自己特有的数据)。

成员变量&局部变量

成员变量和局部变量的区别:

  • 作用范围:成员变量定义在类中,整个类都可访问;局部变量定义在函数、语句、局部代码块中,只在所属的区域有效。
  • 存放位置:成员变量存在于堆内存的对象中;局部变量存在于栈内存的方法中。
  • 生命周期:成员变量随着对象的创建而存在,随着对象的消失而消失;局部变量随着所属区域的执行而存在,随着所属区域的结束而释放。
  • 初始化值:成员变量都有默认初始化值;局部变量没有默认初始化值 。

匿名对象

Example1:当对象对方法仅调用一次时,可简化成匿名对象

Car c = new Car();
c.run();
//可简写为 
new Car().run();

Example2:匿名对象可以作为实际参数进行传递

Car c1 = new Car();
show(c1);
//可简写为
show(new Car()); 

基本数据类型/引用数据类型参数传递

封装

概念:隐藏对象的属性和实现细节,仅对外提供公共访问方式。
好处:将变化隔离;便于使用;提高重用性;提高安全性。
原则:将不需要对外提供的内容都隐藏起来;把属性都隐藏,提供公共方法对其访问。

private(私有)关键字

  • 是一个权限修饰符
  • 用于修饰成员(成员变量和成员函数)
  • 被私有化的成员只在本类中有效

将成员变量私有化,对外提供对应的get/set方法对其进行访问。提高对数据访问的安全性。

封装与私有的区别

  • 私有是封装,封装不是私有。
  • 私有仅仅是封装的一种体现而已。封装是面向对象的一种特征,隐藏实现的细节,但隐藏细节不代表只有私有能做到,只要能做到对方访问不到就能实现封装。(在Java中,最小的封装体是函数,只要知道函数的功能(需要的未知内容,返回值是什么 ))。

构造函数

概念:构建创造对象时调用的函数。
特点:函数名与类名相同;不用定义返回值类型。
作用:给对象进行初始化。
什么时候定义构造函数:在描述事物时,该事物已存在就具备的一些内容,这些内容都定义在构造函数中。

一般函数与构造函数的区别

  • 构造函数:对象创建时,就会调用与之对应的构造函数,对对象进行初始化。
    一般函数:对象创建后,需要函数功能就调用一次。
  • 构造函数:对象创建时,会调用且只调用一次。
    一般函数:对象创建后,可以被调用多次。
public static void main(String[] args)
{
    Person p = new Person();
    p.Person();//错误写法
    p.speak();
    p.speak();
}

注意:默认构造函数的特点;多个构造函数是以重载的形式存在的。

默认构造函数
创建对象必须要通过构造函数初始化。

  • 一个类中如果没有定义过构造函数,那么该类中会有一个默认的空参数构造函数,class Demo{}在编译成Demo.class文件时会自动创建一个成员 Demo(){}
  • 如果在类中定义了指定的构造函数,那么类中的默认构造函数就没有了。

重载:一个类中可以有多个不同的构造函数,给对象不同的初始化,多个构造函数在类中是以重载的形式来体现的,重载的特点为方法名相同,方法参数(参数个数、参数类型)不一样。
内存图解(构造函数会进栈):

Example1

class Person
{
    String name;
    int age;
    public Person()
    {
        name = "旺财";
        age = 1;
        speak();        //可调用
    }
    public void speak()
    {
        Person();       //错误写法,如果要调用,需写成new Person();
        System.out.println(name + ":" + age);
    } 
}

Example2:构造函数中可以写return,但并不常用

class Person
{
    String name;
    int age;
    public Person(String n, int a)
    {
        if(a < 0) return;
        name = n;
        age = a;    
    }
}

this关键字

概念:代表当前对象。this就是所在函数所属对象的引用。简单说:哪个对象调用了this所在的函数,this就代表哪个对象。

什么时候使用this关键字
当在函数内需要用到调用该函数的对象时,就用this。
当成员变量和局部变量重名,可以用关键字this来区分。
用于在构造函数中调用其他构造函数。(注意:只能定义在构造函数的第一行,因为初始化动作要先执行)

内存图解

Example1-1:当前构造函数调用其他构造函数--正确写法

public class Person 
{
    private String name;
    private int age;
    
    Person(String name)
    {
        this.name = name;
    }
    Person(String name,int age)
    {
        /*调用Person(String name){...}的构造函数,注意不能写为this.Person(name),因为构造函数不能通过对象来调用,也不能写为Person(name),因为这个实际上就是this.Person(name)的省略形式*/
        this(name);
        this.age = age;
    }
}

Example1-2:当前构造函数调用其他构造函数--错误写法

public class Person 
{
    private String name;
    private int age;
    
    Person(String name)
    {
        this.name = name;
    }
    Person(String name,int age)
    {
        this.age = age;
        this(name);
    }
}

编译错误:对this的调用必须是构造函数的第一个语句。

static关键字

定义:static是一个修饰符,用于修饰成员(成员变量和成员函数)

class Person 
{
    String name;                  //对象所特有的数据,成员变量(实例变量)
    static String country = "CN"; //静态变量(类变量)
}

被static修饰的成员的特点

  • 随着类的加载而存在
  • 优先于对象存在
  • 被所有对象所共享
  • 可以直接被类名调用(也能被对象调用)

成员变量和静态变量的区别

  1. 两个变量的生命周期不同
    成员变量随着对象的创建而存在,随着对象的被回收而释放。
    静态变量随着类的加载而存在,随着类的消失而消失。

  2. 调用方式不同
    成员变量只能被对象调用。
    静态变量可以被对象和类名调用。

  3. 数据存储位置不同
    成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据。
    静态变量数据存储在方法区(共享数据区)的静态区,所以也叫对象的共享数据。

使用的注意事项

  • 静态方法在访问本类的成员时,只能访问静态成员(非静态方法即可访问静态成员,又可访问非静态成员)
  • 静态方法中不可以写this,super关键字
  • 主函数是静态的

Example1:在静态方法中可通过对象访问非静态方法

class StaticDemo
{
    int num = 4;
    static int data = 10;
    public static void main(String[] args)
    {
        new StaticDemo().show();
        //或 StaticDemo sd = new StaticDemo(); sd.show();
    }
    public void show()
    {
        System.out.println(num); //实际上是this.num
        System.out.println(data);//实际上是StaticDemo.data
    }
}

static的应用——主函数的特殊之处

public static void main(String[] args)

格式固定;被JVM所识别和调用。

  • public:权限必须最大
  • static:不需要对象,直接用主函数所属类名调用即可
  • void:主函数没有具体的返回值( 不然..难道返回给虚拟机?)
  • main:函数名,不是关键字,只是一个jvm识别的固定的名字
  • String[] args:主函数的参数列表,字符串类型数组

默认情况下传入的值为一个空数组,若要传值,可以通过:

javac 类名
java 类名 XX XX ...(字符串参数)

注意:

class MainDemo
{
    public static void main(String[] args)
    {
        ...
    }
    public static void main(int x)        //函数的重载而已,这样写不会报错
    {
        ...
    }
}

内存图解

  • 执行java StaticDemo2后,会开辟空间(栈、堆、方法区(分为非静态区和静态区(存储静态成员))),栈是运行区,方法区是代码置放区。
  • 非静态区和静态区中的方法是所有该类的对象都具有的功能,这些对象唯一的区别是封装的数据不一样。
  • 当执行main方法的第一行时,加载Person类,在classpath路径下找是否有Person.class文件,若没有设置classpath,则在当前目录下找,找到后会把Person.class文件加载进内存。

静态什么时候使用?

  1. 静态变量
    当对象所具备的成员变量的值都是相同的,那么这个成员就需要被静态修饰;如果是不同的,那就是对象的特有数据,必须存储在对象中,是非静态的。

  2. 静态函数
    函数是否用静态修饰,只参考一点——该函数功能是否需要访问到对象的特有数据(即非静态的成员变量),如果需要,该功能就是非静态的;如果不需要,该功能就是静态的,当然也可以将其定义为非静态,但是非静态需要被对象调用,而仅创建对象调用非静态的没有访问特有数据的方法,该对象的创建没有意义,会造成堆空间的浪费。

    class Demo
    {
        int age;
        static int num = 9;
        Demo(int age)
        {
            this.age = age;
        }
        public static void speak()
        {
            System.out.println("hahaha");
        }
    }
    
    class StaticDemo
    {
        public static void main(String[] args)
        {
            //Demo d = new Demo(30);
            //d.speak();
            Demo.speak();
        }
    }
    

静态代码块

特点:随着类的加载而执行,而且只执行一次。
作用:用于给类进行初始化。(构造函数是给对象初始化的,注意有的类可能不需要对象(如,所有的函数都是静态的))

class StaticCode
{
    static int num; //在此处也可以赋值,即static int num = 10,但在此处只能进行一次赋值动作,而在静态代码块里还能对其进行更多的处理
    static
    {
        num = 10;
        num *= 3;
        System.out.println("hahaha");
    }
    static void show()
    {
        System.out.println(num);
    }
}

class StaticCodeDemo
{
    public static void main(String[] args)
    {
        //new StaticCode().show();
        //new StaticCode().show();
        StaticCode.show();
    }
}

一般会用静态代码块对类进行初始化的,那么在这个类中,全是静态成员。

构造代码块

类中的独立代码块。
构造代码块:可以给所有对象进行初始化,具有通用性
构造函数:给对应的对象(调用该构造函数的对象)进行针对性的初始化。
构造代码块比构造函数先执行。

class Person
{
    private String name;
    {
        cry();
    }
    Person()
    {
        name = "baby";
//      cry();
    }
    Person(String name)
    {
        this.name = name;
//      cry();
    }
    public void cry()
    {
        System.out.println("哇哇");
    }
    public void speak()
    {
        System.out.println("name:"+name);
    }
    static void show()
    {
        System.out.println("show run");
    }
}

class StaticCodeDemo
{
    public static void main(String[] arg)
    {
        Person p1 = new Person();
        p1.speak();
        Person p2 = new Person();
        p2.speak();
        new Person();
        //以上会输出三遍“哇哇”
        Person.show(); //不会输出“哇哇”,即不会执行构造代码块中的内容
    }
}

不允许其他类创建某类的对象

class ArrayTool
{
    private ArrayTool(){}//该类中的方法都是静态的,所以该类是不需要创建对象的;为了保证不让其它类创建该类对象,可以将构造函数私有化
    
    public static int getMax(int[] arr)
    {
        ...
    }
    
    public static void selectSort(int[] arr)
    {
        ...
    }
}

你可能感兴趣的:(毕向东Java基础教程-面向对象)