栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Java之面向对象(8)

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java之面向对象(8)

前言(面向对象定义)

  面向对象是在面向过程之后出现的。当事件比较简单的时候,利用面向过程,注重的是事件的具体的步骤/过程,注重的是过程中的具体的行为,以函数为最小单位,考虑怎么做。

  而面向对象注重找“参与者”,将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做,然后通过这个对象来使用这个对象所具有的方法属性等(比如:人(类或对象)有眼睛鼻子(属性),也可以吃饭(方法).所以我们说面向对象有一句通俗的话叫做万物皆对象)。

  下面我们就来详细介绍一下面向对象的概念和使用。

1 面向对象基本使用和相关关键字 1.1 类和对象的概念和使用

类的定义和代码结构

  1. 类是对一个实体(也就是对象)向上抽取出抽象的部分(公共的部分),这样的抽象实体就是类。类是抽象的,是一个模板。
  2. 具体来说类里面有两种特性,即属性和方法。属性是类的静态特征,方法是类的动态特征。

注意:第一次使用类的时候,会进行类的加载,初始化创建对象的时候,对象的属性没有给赋值,会有默认的初始化的值。而第二次使用这个类就不会进行类加载了

完整代码结构:

//类的定义
[修饰符] class 类名{
	//属性的定义
	[修饰符]  属性类型  属性名 = [默认值] ;
	//方法的定义
	[修饰符]  方法返回值类型  方法名(形参列表) {
        // n条语句
	}
}

对象的定义和代码结构

  1. 对象是一个类的具体实例。(EG:定义一个人的类,类里面有吃饭的方法。而对象是张三(一个具体的人),张三是站着吃饭的(具体的吃饭的方法)。)
  2. 创建一个对象需要有类的存在,通过类就可以创建一个对象。用new关键字来实现。

完整代码结构是:

[修饰符] 类名	类对象名 = new 类名(实参列表);

使用类和对象的实例
  1 创建一个类,抽象出人这个实体。
  2 用这个类来构造一个对象,并且使用这个对象的方法。

public class Person {
    //名词---》属性---》成员变量---》放在类中方法外(注意:我们只把有需要的内容写到代码里,不相关的东西不要放在代码中)
    int age ;//年龄
    String name;//姓名
    double height;//身高
    double weight;//体重
    //动词---》方法
    //吃饭
    public void eat(){
        int num = 10;//局部变量:放在方法中
        System.out.println("我喜欢吃饭");
    }
    //睡觉:
    public void sleep(String address){
        System.out.println("我在"+address+"睡觉");
    }
    //自我介绍:
    public String introduce(){
        return "我的名字是:"+name+",我的年龄是:"+age+",我的身高是:"+height+",我的体重是:"+weight;
    }
}


public class Test {
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //创建一个人类的具体的对象/实例:
        //创建一个对象,对象的名字叫:zhangsan
        //Person 属于 引用数据类型
        //第一次加载类的时候,会进行类的加载,初始化创建对象的时候,对象的属性没有给赋值,有默认的初始化的值。
        Person zs= new Person();
        zs.name = "张三";
        zs.age = 19;
        zs.height = 180.4;
        zs.weight = 170.4;
        //再创建一个对象:名字叫:lisi
        //再次创建类的时候,就不会进行类的加载了,类的加载只在第一次需要的时候加载一次
        Person ls = new Person();
        ls.name = "李四";
        ls.age = 18;
        ls.height = 170.6;
        ls.weight = 160.5;
        //对属性值进行读取:
        System.out.println(zs.name); // 张三
        System.out.println(ls.age); // 18
        //对方法进行操作:
        //不同的对象,属性有自己的特有的值,但是方法都是调用类中通用的方法。
        //属性:各个对象的属性是独立的,
        //方法:各个对象的方法是共享的。
        zs.eat(); // 我喜欢吃饭
        ls.eat(); // 我喜欢吃饭
        zs.sleep("教室");  // 我在教室睡觉
        
        System.out.println(zs.introduce()); // 我的名字是:张三,我的年龄是:19,我的身高是:180.4,我的体重是:170.4
    }
}

1.2 局部变量和成员变量的区别
  • 区别1:代码中位置不同
      局部变量:方法中定义的变量
      成员变量:类中(方法外)定义的变量

  • 区别2:代码的作用范围不同
      局部变量:当前的方法内
      成员变量:作用于当前类的所有方法中

  • 区别3:变量是否有默认值
      局部变量:无
      成员变量:有,↓为成员变量的默认值

  • 区别4:变量是否要初始化
    局部变量:一定需要,不然使用的时候会报错
    成员变量:不需要,可以使用的时候对它进行赋值

  • 区别5:内存中的位置不同
    局部变量:栈内存
    成员变量:堆内存

  • 区别6:作用时间不同
    局部变量:当前方法从开始到执行结束
    成员变量:当前类的对象从创建到销毁的整个过程

1.3 构造器

  在创建对象的过程中,是通过类内的一个特殊方法(构造器)来实现创建的。

具体过程见例子:

class Test {
    public static void main(String[] args) {
        //创建一个Person类的具体的对象/实例/实体:
        
        Person p = new Person();
        System.out.println(p.age);
        System.out.println(p.name);
        System.out.println(p.height);
        Person p2 = new Person();
        System.out.println(p2.age);
        System.out.println(p2.name);
        System.out.println(p2.height);
    }
}

  构造器是一个特殊方法,所以也可以重载。但是当你显示的写了一个类的重载构造器之后,默认的空参构造器就需要显示写出来,不然会报错。

  想要指向类对象中的属性时,使用this关键字。this代表你创建的那个对象

public class Person {
    //属性:
    String name;
    int age;
    double height;
    //空构造器
    public Person(){
    }
    public Person(String name,int age,double height){
        //当形参名字和属性名字重名的时候,会出现就近原则:
        //在要表示对象的属性前加上this.来修饰 ,因为this代表的就是你创建的那个对象
        this.name = name;
        this.age = age;
        this.height = height;
    }
    public Person(String a,int b){
        name = a;
        age = b;
    }
    //方法:
    public void eat(){
        System.out.println("我喜欢吃饭");
    }
}
1.4 简单代码的内存分析
public class Person {
        int id;
        int age;
        String school;
        public Person (int a,int b,String c){
                id=a;
                age=b;
                school=c;
        }
        public static void main(String args[]){
                Person p= new Person(1,20, "");
        }
}

  点击运行时从main函数开始的:

(1)先开辟三个空间:栈,堆,和方法区(方法区内有一个地方为常量池)。
(2)在栈中开辟一个空间main方法。
(3)首先看到new Person,在方法区中加载这个Person字节码文件(只有第一次会加载),然后在堆中开辟一个空间来创建一个Person对象(这个对象有一个地址)。这个对象也会反过来指向它的字节码文件,用来指定自己是依靠谁来创建的。
(4)创建好了对象之后,new Person(1,20,"海淀")就去执行它的构造方法。会在栈中开辟一个空间Person构造器方法。
(5)在栈实参传入构造器方法的过程中。
  如果是基本数据类型,那么直接传的就是这个值本身(值传递)。
  如果是引用数据类型,比如String,那么会先在常量池中开辟一个空间来放置"海淀"这个字符串,然后把地址传给c(地址传递)。
(6)构造器执行完毕后,就会在栈中销毁,然后转入main方法。
(7)Person p = 。。。 之后把这个对象的地址赋值给p。(之后就可以通过p来操作这个对象)

整个程序运行的内存图解
1.5 this,static,代码块

this :指的是当前对象

  当属性名字和形式参数发生重名的时候,或者属性名字和局部变量的名字重名的时候,都会发生就近原则,所以我们如果要直接使用属性的话,前面就要用this修饰这个变量。(如果没有重名就无所谓使用了)

this关键字使用的图解

static关键字特点

  1. static可以修饰:属性,方法,代码块,内部类(没有类)
  2. 在方法区内有一个区域为静态域,用于存放static修饰的东西
  3. 用它修饰会在加载某类字节码文件时同时加载到静态域内。先于对象存在。
  4. 应用场景:某些特定的数据想要在内存中共享时就使用static来修饰即可

代码实例:

public class Demo1 {
    int id;
    static int sid;
    public void a(){
        System.out.println(id);
        System.out.println(sid);
        System.out.println("------a");
    }
    // 1.static和public都是修饰符,并列的没有先后顺序,先写谁后写谁都行
    static public void b(){
        //System.out.println(id); // 2.在静态方法中不能访问非静态的属性
        //a(); // 3.在静态方法中不能访问非静态的方法
        //System.out.println(this.id); // 4.在静态方法中不能使用this关键字
        System.out.println(sid);
        System.out.println("------b");
    }
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        //5.非静态的方法可以用对象名.方法名去调用
        Demo1 d = new Demo1();
        d.a();
        //6.静态的方法可以用   对象名.方法名去调用  也可以用  类名.方法名 (推荐)
        Demo1.b();
        d.b();
    }
}

代码块的特点

  1. 类的组成是:属性,方法,构造器,代码块和内部类
  2. 代码块的分类是:普通块,构造块,构造器块,静态块,同步块(多线程)
  3. 代码块的执行顺序是:
      1.最先执行静态块,而且只在类加载的时候执行一次。(一般用于执行一些全局性的初始化操作)
      2.然后执行构造块
      3.再执行构造器方法块
      4.最后执行方法中的普通块
  4. 代码块详细:
      普通块:就是普通方法内的内容
      构造块:在类中单独一个大括号内部的内容
      构造器块:特殊用于构造类对象的方法
      静态块:在类中用一个static{ }结构包裹的内容

代码实例:

public class Demo1 {
    //属性
    int a;
    static int sa;
    //方法
    public void a(){
        System.out.println("我是普通方法a");
        {
            //普通块限制了局部变量的作用范围
            System.out.println("我是普通方法里面的普通块");
        }
    }
    public static void b(){
        System.out.println("我是静态方法b");
    }
    //构造块
    {
        System.out.println("我是类下的构造块,{}");
    }
    //静态块
    static{
        System.out.println("我是类下的静态块,static{}");
        //在静态块中只能方法:静态属性,静态方法
        System.out.println("我是类下的静态块,只能调用静态属性"+sa);
    }
    //构造器
    public Demo1(){
        System.out.println("我是类下的空构造器");
    }
    public Demo1(int a){
        this.a = a;
    }
    //这是一个main方法,是程序的入口:
    public static void main(String[] args) {
        Demo1 t = new Demo1();
        t.a();
        System.out.println("------------------第二次---------------");
        Demo1 t2 = new Demo1();
        t2.a();
    }
}
1.6 包,import

包的定义和特点

  1. 包的作用:就是为了分类,然后也为了解决重名问题和权限问题(包其实就相当于电脑盘符的目录)
  2. 包的命名:
    (1)名字全部小写
    (2)中间用 . 隔开
    (3)一般都是公司域名倒着写 : com.jd com.uestc
    (4)加上模块名字:com.jd.login com.jd.register
    (5)不能使用系统中的关键字:nul con com1至com9…
    (6)包声明的位置一般都在非注释性代码的第一行:
  3. 想使用同一个包下的类不需要导包,可以直接使用。使用不同包下的类要需要导包: import **.**.**; 例如:import java.util.Date;
  4. 在java.lang包下的类,可以直接使用无需导包。
System.out.println(Math.random());
  1. IDEA中导包快捷键:alt+enter
  2. import 。。。.*代表所有
import java.util.*
  1. 导包中的目录没有包含和被包含的关系
import com.jayden.*  //只代表jayden这一层的类,如果里面有还有包,那么这个包并没有加入
import com.jayden.sub.D //因为如果jayden下如果分别有两个包,两个包都有sub方法就会导致歧义
  1. 包可以静态引用
//静态导入:
import static java.lang.Math.*;
//导入:java.lang下的Math类中的所有静态的内容
public class Test {
    public static void main(String[] args) {
        System.out.println(random());
        System.out.println(PI);
  		System.out.println(round(5.6));
    }
    //在静态导入后,同一个类中有相同的方法的时候,会优先走自己定义的方法。
    public static int round(double a){
        return 1000;
    }
}
2 三大特性

  面向对象的三大特性是指:封装,继承,多态。

2.1 封装(Encapsulation)

封装的定义:封装就是具体的内部不给你看,只提供有限的接口供你使用的一种设计思想。

封装的特点

  1. 设计程序是要求“高内聚,低耦合”。
      高内聚:类的内部数据操作细节自己完成,不允许外部干涉。
      低耦合:仅对外暴露少量的方法用于使用。
      隐藏对象内部的复杂性,只对外提供有限的接口。方便外界调用,从而提高系统的安全性、可扩展性、可维护性。通俗来说就是该隐藏的隐藏,该暴露的暴露。
  2. 代码中通过private权限修饰符来限制
  3. 权限修饰符

  一般属性用private修饰,方法用public修饰

代码实例:

public class Girl {

    //属性: private:私有化,外界不可以直接访问
    private int age;

    //读取年龄: public:外界可以直接访问
    public int getAge(){
        return age;
    }
    //设置年龄:
    public void setAge(int age){
        if(age >= 30 ){
            this.age = 18;
        }else{
            this.age = age;
        }
    }
}

public class Demo1 {
    public static void main(String[] args) {
        //创建一个Girl类的对象:
        Girl g = new Girl();
        
        //设置年龄:
        g.setAge(31);
        //读取年龄:
        System.out.println(g.getAge());
    }
}

  上面的代码,对于属性age来说,我加了修饰符private,这样外界对它的访问就受到了限制,现在我还想加上其他的限制条件,但是在属性本身上没有办法再加了,所以我们通过定义方法来进行限制条件的添加。
  以属性为案例:
进行封装:
(1)将属性私有化,被private修饰(加入权限修饰符)
一旦加入了权限修饰符,其他人就不可以随意的获取这个属性
(2)提供public修饰的方法让别人来访问/使用
(3)即使外界可以通过方法来访问属性了,但是也不能随意访问,因为咱们在方法中可以加入限制条件。

2.2 继承(Inheritance)

继承的定义:继承就是对类的进一步抽象,多个类可以能有相同的属性和方法,这个时候就可以对这几个类抽取出所谓的父类。

EG: 
**学生类**:Student:
	属性:姓名,年龄,身高,学生编号
	方法:吃饭,睡觉,喊叫,学习
**教师类**:Teacher:
	属性:姓名,年龄,身高,教师编号
	方法:吃饭,睡觉,喊叫,教学
共同的东西:**人类**:Person
	属性:姓名,年龄,身高
	方法:吃饭,睡觉,喊叫

  学生和老师都是人,如果还有100种职业的话,比如都有属性姓名属性和吃饭的方法,那么每一个类中都要重新写一遍就太麻烦了,所以定义它们的父类Person,只要用字段entend关键字继承Person,就会获得Person的所有共有属性和方法。

继承的特点

  1. 继承的好处:提高了代码的复用性和可扩展性。类定义的内容,子类可以直接拿过来用就可以了,不用代码上反复重复定义了。也是多态的前提。
  2. 继承只能有一个直接父类
//报错,只能有一个直接父类
public class Student extends Person,Boss{
}
  1. 继承具有传递性:EG:Student继承自Person,Person继承自Object(所有的类都直接或者间接的继承自Object)

内存分析:在new一个子类对象的时候,会先加载这个子类所有父类的字节码,然后再加载这个子类的字节码。

注意:父类private修饰的内容,子类实际上也继承,只是因为封装的特性阻碍了直接调用,但是提供了间接调用的方式,可以间接调用。

方法重写的定义和特点:

  1. 发生在子类和父类中,当子类对父类提供的方法不满意的时候,要对父类的方法进行重写。
  2. 子类的方法名字和父类必须一致,参数列表(个数,类型,顺序)也要和父类一致。

代码实例:

class Person {
    public void eat(){
        System.out.println("吃食物");
    }
}
class Student extends Person {
    @Override
    public void eat(){
        System.out.println("我喜欢吃小龙虾喝啤酒。。");
    }
}
public class Demo1 {
    public static void main(String[] args) {
        //创建一个Student类的对象:
        Student s = new Student();
        //打印的是子类Student中重写的的eat方法,而不是父类Person的
        s.eat(); // 我喜欢吃小龙虾喝啤酒。。
    }
}

重载和重写的区别:重载(Overload)是在同一个类中方法名相同,单参数列表不同的多个方法构成的结构。而重写(Override)是在不同类中,方法名和参数名都必须相同(注意:重写中父类的修饰符权限一定要低于子类的,返回值类型要大于子类的)

super关键字的定义和特点

  1. 在子类的方法中,可以通过 super.属性 super.方法 的方式,显示的去调用父类提供的属性,方法。在通常情况下,super.可以省略不写。
  2. 在特殊情况下,当子类和父类的属性和方法重名时,你要想使用父类的属性,必须加上修饰符super.,只能通过super.属性来调用。
  3. 其实我们平时写的构造器的第一行都有(super();)代码。作用是调用父类的空构造器(只是我们一般都省略不写)。如果构造器中已经显示的调用super父类构造器,那么它的第一行就没有默认分配的(super();)了
  4. 在构造器中,super调用父类构造器和this调用自身构造器只能存在一个。(因为super和this修饰构造器都要放在第一行)
public Student(int age,String name,double score){
	super(age,name);
	this(score);//调用子类的public Student(double score)构造器报错
}
2.3 多态(Polymorphism)

多态的定义:多态就是对同一个方法的不同实现。(继承是多态的前提)

多态的特点

  1. 多态只和方法有关,和属性无关。
  2. 多态的好处:提高了代码的可扩展性,符合面向对象的设计原则:开闭原则(可以扩展,但是原来存在的不准修改)

代码实例:多态的应用

class Animal {//父类:动物:
    public void shout(){
        System.out.println("我是小动物,我可以叫。。。");
    }
}
class Cat extends Animal{//子类1:猫
    //喊叫方法:
    public void shout(){
        System.out.println("我是小猫,可以喵喵叫");
    }
}
class Dog extends Animal{//子类2:狗
    int age;
    int weight;
    //喊叫:
    public void shout(){
        System.out.println("我是小狗,我可以汪汪叫");
    }
    public void eat(){
        System.out.println("我是小狗,我爱吃东西。。");
    }
}
class Girl { //多态应用1:原本要写两个方法现在只需要写一个
    //跟猫玩耍:
    
    //跟狗玩耍:
    
    //跟小动物玩耍:
    public void play(Animal an){
        an.shout();
    }
}
public class Demo1 {
    public static void main(String[] args) {
        //eg1:转化为父类根据对象使用对应的方法
        Cat cat = new Cat();
        Dog dog = new Dog();
        //Animal an = ?
        Animal animal = dog;//转型:向上转型(Dog转成Animal)
        //多态应用2:下面代码就不用变了
        animal.shout();
        //注意an只能用Animal中存在的方法,虽然它的对象是Dog,但在编译期的时候因为Animal没有eat属性所以会报错
//        an.eat();
        
        //eg2:转化为子类后可以用子类的方法
        Dog dog2 = (Dog)animal ;//转型:向下转型(Animal转为Dog)
        dog2.eat();
    }
}
2.4 简单工厂模型(多态应用)

  多态的应用中,不仅可以使用父类做方法的形参,还可以使用父类做方法的返回值类型,真实返回的对象可以是该类的任意一个子类对象。
  这种方法是简单工厂模式的实现,它是解决大量对象创建问题的一个解决方案。将创建和使用分开,工厂负责创建,使用者直接调用即可。简单工厂模式的基本要求是
(1)定义一个static方法,通过类名直接调用
(2)返回值类型是父类类型,返回的可以是其任意子类类型
(3)传入一个字符串类型的参数,工厂根据参数创建对应的子类产品
代码实例:

class PetStore {//宠物店 ---》工厂类
    //方法:提供动物
    public static Animal getAnimal(String petName){//多态的应用场合(二)
        Animal an = null;
        if("猫".equals(petName)){//petName.equals("猫") --》这样写容易发生空指针异常
            an = new Cat();
        }
        if("狗".equals(petName)){
            an = new Dog();
        }
        return an;
    }
}
class Demo2 {
    public static void main(String[] args) {
        Girl g = new Girl();
        //Cat c = new Cat();
        //Dog d = new Dog();
        Animal an = PetStore.getAnimal("狗");
        g.play(an); // 我是小狗,我可以汪汪叫
    }
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1030382.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号