Java基础重构-面向对象(上)

简介: Java 是面向对象的程序设计语言,类是面向对象的重要内容,可以把了当成一种自定义类型。可以使用类来定义变量,这种类型的变量统称为引用变量。

Java 是面向对象的程序设计语言,类是面向对象的重要内容,可以把了当成一种自定义类型。可以使用类来定义变量,这种类型的变量统称为引用变量。


static 是一个特殊的关键字,它可用于修饰方法,成员变量等成员。static 修饰的成员表明他属于这个类本省,而不属于该类的单个实例,因为通常把 static 修饰的成员变量和 方法 也成为类变量,类方法。不使用 static 修饰的普通方法,成员变量则属于该类的单个实例,而不属于该类。因为通常把不使用 static修饰的成员变量和方法也成为实例变量,实例方法。

对象的this引用是什么?

Java 提供了一个this 关键字,this关键字总是指向调用该方法的对象,更具 this 出现位置的不同,this作为对象的默认引用有两种情形。

  1. 构造器中引用该构造器正在初始化的对象
  2. 在方法中引用调用该方法的对象。

this关键字最大的作用就是让类中一个方法,访问该类里的另一个方法或实例变量。

this可以代表任何对象,当this出现在某个方法体重是,它所代表的对象是不确定的,但它的类型是确定的,他所代表的对象 只能是当前类;只有当这个方法被调用时,它所代表的对象才被确定下来,谁在调用这个方法,this就代表谁。

大部分时候,一个方法访问该类中定义的其他方法,成员变量时加不加this前缀的效果是完全一样的。但是对于static 修饰的方法而言,则可以使用类来直接调用该方法,如果在 static 修饰的方法中使用 this关键字,则这个关键字就无法指向合适的对象。所以,satatic 修饰的方法不能使用 this引用,所以static 修饰的方法不能访问不使用 static 修饰的普通成员,因此 Java 语法规定: 静态成员不能直接访问非静态成员。

也可以将 this 作为返回值,如果某个方法把 this 作为返回值,则可以多次连续调用同一个方法,从而使得代码更加简洁。但是,这种把 this作为返回值的方法可能造成实际意义上的模糊。

public class MyClass {
    private static int age;
    public static void main(String[] args) {
        new MyClass().vo().vo().vo();
    }
    private MyClass vo() {
        ++age;
        System.out.println(age);
        return this;
    }
}

为什么static成员不能直接访问非静态成员?

static 是一个特殊的关键字,它可用于修饰方法,成员变量等成员。static 修饰的成员表明他属于这个类本身,而不属于该类的单个实例。而我们非static 修饰的变量它属于的是实例的变量,所以stati成员不能直接

访问静态成员

为什么同一类里,静态和非静态方法可以相互调用?

因为Java里的方法不能独立存在,他必须属于一个类或一个对象,因此方法不能像函数那样被独立执行,执行方法时必须使用类或对象来作为调用者,同一个类的一个方法调用另外一个方法时,如果被调方法时普通方法,则使用默认使用 this 作为调用者;如果被调方法是静态方法,则默认使用类作为调用者。也就是说,表面上看起来某些方法可以被独立执行,但实际上环视使用this或者 类 作为调用者。

Java的参数传递中可以引用传递吗?

不可以,Java的参数传递方式只有一种,值传递。所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本身不会受到影响。


我们有时候见到 使用 参数传递 某些对象。看起来好像是引用传递,但其实不是,这里传递的也只是一个对象在内存中的的地址而已,并不是真正的把 对象引用传递过去。

形参个数可变的参数是什么?

Jdk1.5 之后,Java允许定义形参个数可变的参数,从而允许为方法指定数量不确定的形参。如果在定义方法时,在最后一个形参的类型后增加三点 (…),则表明该形参可以接受多个参数值,多个参数值被当成数组传入。

public class MyClass {
    private static int age;
    public static void main(String[] args) {
        Demo(2,3,4);
        Demo(new int[]{12,2});
    }
    static void Demo(int... a2) {
        for (int i : a2) {
            System.out.println(i);
        }
    }
}

但需要注意的是,长度可变的形参只能处于形参列表的最后。一个方法最多只能包含一个长度可变的形参。长度可变的形参本质就是一个数组类型的形参,因此调用包含一个长度可变形参的方法时,这个长度可变的形参即可以传入多个参数,也可以传入一个数组。

为什么方法的返回值类型不能用于区重载的方法?

对于 int f()和 void f() 两个方法,如果 int a=f(),系统可以识别是调用返回值类型为 int 的方法;但Java 调用方法时 可以忽略 方法的返回值,如果直接调用 f(),那么谁有知道到底是调用了那个方法呢?

为什么需要添加set get方法?

Java类里实例变量的 set 和get方法有着非常重要意义,例如,某个类里包含了一个名为 abc 的实例变量,则其对应的 set和get 方法名应为setAbc() 和 getAbc().

如果一个类 Java 类的每个实例 变量都被使用 private 修饰,并为每个实例变量都提供了 public 修饰的 set 和 get方法,那么这个类就是一个 符合 JavaBean 规范的类,因此,JavaBean 总是一个封装良好的类。

一个类常常就是一个小的模块,应该只让这个模块公开必须让外界知道的内容,而隐藏其他的一切内容。进行程序设计时,应尽量避免一个模块直接操作和访问另一个模块的数据,模块设计追求高内聚(尽可能把模块之间的内部数据,功能实现细节隐藏在模块内部独立完成,不允许外部直接干预),低耦合(仅暴露少量的方法给外部使用)。

构造器创建Java对象的途径,是不是说构造器完全负责 Java对象?

不是,构造器是创建 Java 对象的重要途径,通过 new 关键字调用构造器时,构造器也确实返回了 该类的对象,但这个对象并不是完全由构造器负责创建的。实际上,当程序员调用构造器时,系统会先为该对象分配内存空间,并为这个对象执行默认初始化,这个对象已经产生了——这些操作系统在构造器的执行前就都已经完成了。也就是说,当系统开始执行构造器的执行体之前,系统已经创建了一个对象,只是这个对象还不能被外部程序访问,只能在该构造器中通过this 来引用。当构造器的执行体结束后,这个对象作为构造器的返回值而被返回,通常还会赋给另一个引用类型的变量,从而让外部程序可以访问该对象。

super限定的用处?

如果需要在子类方法中调用 父类被覆盖的实例方法。则可使用 super 限定来调用父类被覆盖的实例方法。

package com.example.javatest;
public  class Demo extends A{
    public static void main(String[] args) {
        new Demo().test();
    }
    public void test(){
        super.test();
        System.out.println("Demo");
    }
}
class  A{
    public void test(){
        System.out.println("A");
    }
}

什么是多态?

Java 引用变量有两个类型,一个是编译型类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给变量的对象决定。如果编译时类型和运行时类型不一样。就可能出现所谓的多态。

当把一个子了i对象那个直接赋给父类引用变量时,运行时调用该引用变量的方法是,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征。

instanceof 运算符是干什么的?

判断是否是可以成功转换

instanceof 运算符的前一个操作数通常是一个 引用类型变量,后一个操组数通常是一个类(也可以是接口,可以把接口理解成一种特殊的类),它用于判断前面的对象是否是后面的类,或者其子类,实现类的实例。如果是,返回 true,否则 返回false

public class Demo {
    public static void main(String[] args) {
        Object a=new String("123");
        if (a instanceof Integer) {
            System.out.println("123");
        }
    }
}

谈谈你对继承的理解?

继承最大的好处就是类的复用性,子类可以直接调用父类的所有成员变量和方法。但是继承带来高度复合的同事,也带来了一个严重的问题:继承严重破坏了父类的封装性。Java 里对封装的定义是:每个类都应该封装它内存信息和实现细节,而只暴露必要的方法给其他类使用。但在继承关系中,子类可以直接访问父类的成员变量(内部信息)和方法,从而造成子类和父类的严重耦合。

所以我们在使用继承的时候。首先得明白:子类是一种能特殊的父类。

对于具备以下条件之一才使用继承,否则使用 组合 也能实现类的复用。

  • 子类需要额外增加属性,而不仅仅是属性值的改变。
  • 子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)

谈谈你对组合的理解?

把一个类当做一个类的组合成分,从而允许新类直接复用该类的 public 方法,这种就是组合。

一般用到组合的地方,用继承也可以实现,简单来说,继承是对已有类的一番改造,以此获得一个特殊的类。简而言之,就是将一个较为抽象的类改造成能适用于某些特定需求的类,比如在原来基础上增加别的成员变量或者方法等。反之,如果两个类之间有明确的整体,部分的关系,此时就应该采用组合关系来实现复用。

总之,继承要表达的是 (is-a)的关系,而组合表达的是 有 (has-a)的关系。(is-a代表的是继承关系,has-a代表的是对象和它成员的从属关系)

什么是自动装箱?

自动装箱,就是可以把一个基本类型变量直接赋给对应包装类变量,或者赋给Object变量,(Object是所有类的父类,自诶对象可以直接符给父类变量),自动拆箱则则与之相反,允许直接·把包装类对象直接赋给一个对应的基本类型变量。

简单讲一下==与 equals 方法有什么不同?

Java程序测试两个变量是否相等有两种方式,一种是利用== 运算符,另一种就是利用 equals方法,当时用 判断两个变量是否相等时,如果两个变量时基本类型变量,且都是数据类型,则只要两个变量的值相等,就将返回 true。但对于引用类型变量,只要他们指向同一个对象, 判断才会返回true,== 不可用与比较类型上没有父子·关系的两个对象。euqals 判断的是引用对象里包含的字符序列是否相同,相同就返回true,

简单讲一下 final 修饰符

final修饰符可用于修饰类,变量和方法。final 修饰的变量度不可被改变,一旦获得了初始值,该 final 变量的值就不能被重新赋值。final修饰的成员变量必须由程序员显示的指定初始值,因为系统不会为 final 修饰的变量隐式初始化。

final修饰基本引用类型和运用类型变量有什么区别?

当时用final 修饰基本类型数据时,不能对基本类型变量重新赋值,因此基本类型变量不能被改变。但对于引用类型变量而言,它保存的仅仅是一个引用,final 只保证这个引用类型变量所引用的地址不会改变,即一直引用同一个对象,但这个对象完全可以发生改变。

为什么被final修饰的变量 被称为 执行宏替换 的变量?

当定义final 变量时就为该变量指定了初始值,而且该初始值可以在编译期间确定下来,那么这个 final 变量本质上就是一个 宏变量 ,编译器会把程序中所有用到该变量的地方直接替换为该变量的值。

谈谈你对抽象类与抽象方法的理解?

  1. 抽象类必须是 abstact 修饰符来修饰,抽象方法也必须使用 abstract 修饰符来修饰,抽象方法不能有方法体。
  2. 抽象类·不能被实例化,无法使用 new 关键字来调用 抽象类的构造器创建抽象类的实例。
  3. 抽象类可以包含成员变量,方法(普通方法和抽象方法都可以),构造器,初始化块,内部类(接口,枚举)5种成分。抽象类的构造器不能用于创建实例,主要是用于被其子类调用。
  4. 含有抽象方法的类(包括直接定义了一个抽象方法;或继承了一个抽象方法,但没有完全实现父类包含的抽象方法;或实现了一个接口,但没有完全实现接口包含的抽象方法三种情况)只能被定义成抽象类。

需要注意的是:

  • static 和 abstract 不能同时修饰某个方法。
  • static 和 abstract 可以同时修饰内部类
  • abstract 关键字修饰的方法必须被其子类重写才有意义,否则这个方法将永远不会有方法体。
目录
相关文章
|
16天前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
19 1
|
28天前
|
JavaScript 前端开发 Java
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。如果你从我的文章中受益,欢迎关注我,我将持续更新更多优质内容。你的支持是我前进的动力!🎉🎉🎉
24 0
还不明白面向对象? 本文带你彻底搞懂面向对象的三大特征(2024年11月Java版)
|
2月前
|
存储 缓存 Java
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
这篇文章详细介绍了Java中的IO流,包括字符与字节的概念、编码格式、File类的使用、IO流的分类和原理,以及通过代码示例展示了各种流的应用,如节点流、处理流、缓存流、转换流、对象流和随机访问文件流。同时,还探讨了IDEA中设置项目编码格式的方法,以及如何处理序列化和反序列化问题。
89 1
java基础:IO流 理论与代码示例(详解、idea设置统一utf-8编码问题)
|
1月前
|
Java 关系型数据库 数据库
面向对象设计原则在Java中的实现与案例分析
【10月更文挑战第25天】本文通过Java语言的具体实现和案例分析,详细介绍了面向对象设计的五大核心原则:单一职责原则、开闭原则、里氏替换原则、接口隔离原则和依赖倒置原则。这些原则帮助开发者构建更加灵活、可维护和可扩展的系统,不仅适用于Java,也适用于其他面向对象编程语言。
37 2
|
3月前
|
Java 编译器
封装,继承,多态【Java面向对象知识回顾①】
本文回顾了Java面向对象编程的三大特性:封装、继承和多态。封装通过将数据和方法结合在类中并隐藏实现细节来保护对象状态,继承允许新类扩展现有类的功能,而多态则允许对象在不同情况下表现出不同的行为,这些特性共同提高了代码的复用性、扩展性和灵活性。
封装,继承,多态【Java面向对象知识回顾①】
|
3月前
|
Java
java中面向过程和面向对象区别?
java中面向过程和面向对象区别?
36 4
|
3月前
|
Java
接口和抽象类【Java面向对象知识回顾②】
本文讨论了Java中抽象类和接口的概念与区别。抽象类是不能被实例化的类,可以包含抽象和非抽象方法,常用作其他类的基类。接口是一种纯抽象类型,只包含抽象方法和常量,不能被实例化,且实现接口的类必须实现接口中定义的所有方法。文章还比较了抽象类和接口在实现方式、方法类型、成员变量、构造方法和访问修饰符等方面的不同,并探讨了它们的使用场景。
接口和抽象类【Java面向对象知识回顾②】
|
2月前
|
存储 Java 程序员
Java基础-面向对象
Java基础-面向对象
19 0
|
3月前
|
设计模式 监控 Java
重构与优化-前言(java)
重构与优化-前言(java)
|
3月前
|
Java 开发者
Java 面向对象
Java 是一种面向对象的编程语言,通过对象与类的概念组织代码和数据。面向对象编程的核心包括类、对象、继承、多态、封装和抽象。类是对象的蓝图,定义了属性和行为;对象则是类的实例。继承允许子类继承父类的属性和方法,增强代码复用性;多态则支持通过相同接口调用不同类型对象的行为,包括方法重载和重写。封装通过公共方法隐藏对象细节,提高安全性;抽象则对对象特征进行提炼,通过抽象类和接口实现。理解这些概念有助于设计高效、可维护的 Java 应用程序。
23 0