zoukankan      html  css  js  c++  java
  • Java 工程师成神之路

    基础篇

    → 什么是面向对象

    面向对象、面向过程

    是一种新兴的程序设计方法,或者是一种新的程序设计规范(paradigm),其基本思想是使用对象、类、继承、封装、多态等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。

    对象

    对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和 对这组属性进行操作的一组服务 组成。

    类是具有相同属性和方法的一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和方法两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性和方法两个主要部分。

    Java中的类实现包括两个部分:类声明和类体。

    面向过程
    自顶向下、逐步求精、模块化封装函数主张按功能把软件系统逐步细分,对每个涉及到的功能都进行一次数据处理然后输出。由主函数负责把函数中的所有接口串接起来,程序的实现非常强调达到某功能的算法。每个函数都有唯一的入口和出口。

    面向对象的三大基本特征和五大基本原则

    三大特性是:封装,继承,多态  

    所谓封装,也就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。封装是面向对象的特征之一,是对象和类概念的主要特性。 简单的说,一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。


    所谓继承是指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过“继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力;

    所谓多态就是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。


    五大基本原则 
    单一职责原则SRP(Single Responsibility Principle)
    是指一个类的功能要单一,不能包罗万象。如同一个人一样,分配的工作不能太多,否则一天到晚虽然忙忙碌碌的,但效率却高不起来。

    开放封闭原则OCP(Open-Close Principle) 
    一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的。比如:一个网络模块,原来只服务端功能,而现在要加入客户端功能,
    那么应当在不用修改服务端功能代码的前提下,就能够增加客户端功能的实现代码,这要求在设计之初,就应当将服务端和客户端分开,公共部分抽象出来。

    替换原则(the Liskov Substitution Principle LSP) 
    子类应当可以替换父类并出现在父类能够出现的任何地方。比如:公司搞年度晚会,所有员工可以参加抽奖,那么不管是老员工还是新员工,
    也不管是总部员工还是外派员工,都应当可以参加抽奖,否则这公司就不和谐了。

    依赖原则(the Dependency Inversion Principle DIP) 具体依赖抽象,上层依赖下层。假设B是较A低的模块,但B需要使用到A的功能,
    这个时候,B不应当直接使用A中的具体类: 而应当由B定义一抽象接口,并由A来实现这个抽象接口,B只使用这个抽象接口:这样就达到
    了依赖倒置的目的,B也解除了对A的依赖,反过来是A依赖于B定义的抽象接口。通过上层模块难以避免依赖下层模块,假如B也直接依赖A的实现,那么就可能造成循环依赖。一个常见的问题就是编译A模块时需要直接包含到B模块的cpp文件,而编译B时同样要直接包含到A的cpp文件。

    接口分离原则(the Interface Segregation Principle ISP) 
    模块间要通过抽象接口隔离开,而不是通过具体的类强耦合起来

    → 平台无关性

    无论哪种编程语言编写的应用程序都需要经过操作系统和处理器来完成程序的运行,因此这里所指的平台是由操作系统核处理器来完成CPU所构成。与平台无关是指软件的运行不因操作系统,处理系统变化而变化而无法运行或者出现运行错误。
    每个平台都会形成自己独特的机器指令,所谓平台的机器指令就是可以被该平台直接识别,执行的一种由0.1组成的序列代码。相同的CPU和不同的操作系统所形成的平台的机器指令可能是不同的。比如,某个平台可能用8位序列代码00001111表示加法指令,以10000001表示减法,而另一种平台可能用8位序列代码10101010表达加法指令,以10010011表示减法指令。
     
    Java 如何实现的平台无关
    java虚拟机与字节码
    Java语言和其他的语言相比,最大的优势就是它的平台无关性。这是因为java可以在平台之上再提供一个Java运行环境,该java运行环境由Java虚拟机,类库以及一些核心文件组成。Java虚拟机的核心是所谓的字节码指令,即可以被Java虚拟机直接识别,执行的一种由0.1组成的序列代码。字节码并不是机器指令,因为他不和特定的平台相关,不能被任何平台直接识别执行。Java针对不同的平台提供的Java虚拟机的字节码指令都是相同的,比如所有的虚拟机都将11110000识别,执行行为加法操作。
    和C/C++不同的是,Java语言提供的编译器不针对特定的操作系统和CPU芯片进行编译,而是针对Java虚拟机吧Java源程序编译成字节码的“中间代码”,比如Java源程序的文件中的+被编译的自己码指令11110000.字节码是可以被Java虚拟机识别执行的代码,即Java虚拟机负责解释运行字节码,其运行原理:java虚拟机负责将字节码翻译成虚拟机所在平台的机器码,并让当前平台运行该机器码。
    在一个计算机编译得到的字节码的文件可以复制到任何一个安装了一个Java虚拟机的运行环境的计算机直接使用。字节码由Java虚拟机负责解释运行,即Java虚拟机负责将字节码翻译成计算机本地的机器码,并将机器码交给本地的操作系统运行。
     
     
    JVM 还支持哪些语言(Kotlin、Groovy、JRuby、Jython、Scala)
     

    → 值传递

     

    值传递、引用传递

    值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
    引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
     

    内存方面:
    值类型数据是在栈上分配内存空间,它的变量直接包含变量的实例,使用效率相对较高。
    引用类型数据是分配在堆上,引用类型的变量通常包含一个指向实例的指针,变量通过指针来引用实例。

    JAVA中只有值传递,没有引用传递。基本数据类行传递的是拷贝值,引用数据类型传递的是引用的地址值;
    public static void main(String[] args) {
       ParamTest pt = new ParamTest();
    
       User hollis = new User();
       hollis.setName("Hollis");
       hollis.setGender("Male");
       pt.pass(hollis);
       System.out.println("print in main , user is " + hollis);
    } 

    public void pass(User user) { user = new User(); user.setName("hollischuang"); user.setGender("Male"); System.out.println("print in pass , user is " + user);

    输出结果如下:

    print in pass , user is User{name='hollischuang', gender='Male'}  print in main , user is User{name='Hollis', gender='Male'}
    值传递是将变量的一个副本传递到方法中,方法中如何操作该变量的副本,都不会改变原变量的值。(例子:定义一个方法xxx,参数是int a,方法体是a++的,在主函数里定义一个int a=1,把a传入方法xxx,再打印a,a的结果还是1。)
    引用传递是将变量的内存地址传递给方法,方法操作变量时会找到保存在该地址的变量,对其进行操作,会对原变量造成影响。
    java中只有值传递,也就是不管传什么样的变量(基本类型和引用类型),传递的都是变量的副本。传基本类型变量,对该变量,方法改变的只是变量的副本;传引用类型变量,传递的是引用(内存地址)的副本,但不管是不是副本,传的地址值是一样,方法会通过地址找到变量,然后再运用点操作符对变量本身进行操作。(引用是保存在栈上,对象是保存在堆中,引用指向堆上的对象。Java中没有指针,Java是通过点操作符访问并修改对象。若只是单独给变量赋值,修改的是引用,也就是让变量指向了其他对象,对原对象没有影响)
     
     

    为什么说 Java 中只有值传递

    值传递和引用传递说的很清楚

    也解释了为什么说Java中只有值传递

    → 封装、继承、多态

    什么是多态、方法重写与重载

    多态

    概念

    同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。

     多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。

    向上转型存在一些缺憾,那就是它必定会导致一些方法和属性的丢失,而导致我们不能够获取它们。所以父类类型的引用可以调用父类中定义的所有属性和方法,对于只存在与子类中的方法和属性它就望尘莫及了

    指向子类的父类引用由于向上转型了,它只能访问父类中拥有的方法和属性,而对于子类中存在而父类中不存在的方法,该引用是不能使用的,尽管是重载该方法。若子类重写了父类中的某些方法,在调用该些方法的时候,必定是使用子类中定义的这些方法(动态连接、动态调用)

    实现:

    Java实现多态有三个必要条件:继承、重写、向上转型。

     继承:在多态中必须存在有继承关系的子类和父类。

     重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。

     向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才能够具备技能调用父类的方法和子类的方法。

             只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。

             对于Java而言,它多态的实现机制遵循一个原则:当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的,也就是说被子类覆盖的方法。

    为什么要用多态?

    原因:封装可以隐藏实现细节,使得代码模块化;继承可以扩展已存在的代码模块(类);它们的目的都是为了——代码重用。

    而多态除了代码的复用性外,还可以解决项目中紧偶合的问题,提高程序的可扩展性.。耦合度讲的是模块模块之间,代码代码之间的关联度,通过对系统的分析把他分解成一个一个子模块,子模块提供稳定的接口,达到降低系统耦合度的的目的,模块模块之间尽量使用模块接口访问,而不是随意引用其他模块的成员变量。

    多态在什么地方用?

    可以用在方法的参数中和方法的返回类型中。

    根据 Java 多态机制,继承链中对象方法的调用存在一个优先级:

    this.method(O) -> super.method(O) -> this.method((super)O) -> super.method((super)O)

    当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,但是这个被调用的方法必须是在超类中定义过的。

    https://www.jianshu.com/p/976eec24d9d7

    Java的多态性体现在两个方面:由方法重载实现的静态多态性(编译时多态)和方法重写实现的动态多态性(运行时多态)。

    • 编译时多态:在编译阶段,具体调用哪个被重载的方法,编译器会根据参数的不同来静态确定调用相应的方法。
    • 运行时多态:由于子类继承了父类所有的属性(私有的除外),所以子类对象可以作为父类对象使用。程序中凡是使用父类对象的地方,都可以用子类对象来代替。一个对象可以通过引用子类的实例来调用子类的方法。

      重载(Overloading)

    • 方法重载是让类以统一的方式处理不同数据类型的手段。
    • 一个类中可以创建多个方法,它们具有相同的名字,但具有不同的参数和不同的定义。调用方法时通过传递给它们的不同参数个数和参数类型来决定具体使用哪个方法。
    • 返回值类型可以相同也可以不相同,无法以返回型别作为重载函数的区分标准。

      重写(Overriding)

    • 子类对父类的方法进行重新编写。如果在子类中的方法与其父类有相同的的方法名、返回类型和参数表,我们说该方法被重写 (Overriding)。
    • 如需父类中原有的方法,可使用super关键字,该关键字引用了当前类的父类。
    • 子类函数的访问修饰权限不能低于父类的。

    Java 的继承与实现

    构造函数与默认构造函数

    类变量、成员变量和局部变量

    成员变量和方法作用域

  • 相关阅读:
    「JavaSE 重新出发」05.03.02 在运行时使用反射分析对象
    「JavaSE 重新出发」05.03.01 利用反射分析类
    「JavaSE 重新出发」05.03 反射
    「JavaSE 重新出发」05.02 泛型数组列表、包装类
    scp 命令简明介绍
    《鸟哥的Linux私房菜》笔记——04. 简单命令行
    《鸟哥的Linux私房菜》笔记——03. 磁盘分区
    「JavaSE 重新出发」05.01.02 hashCode 方法、toString 方法
    「JavaSE 重新出发」05.01.01 equals 方法
    「JavaSE 重新出发」05.01 继承
  • 原文地址:https://www.cnblogs.com/alter888/p/10398000.html
Copyright © 2011-2022 走看看