美文网首页java基础
java类的基本构成

java类的基本构成

作者: LeoFranz | 来源:发表于2019-06-22 11:57 被阅读0次

    导言

    • 面向对象思想理解:面向对象是一种程序设计规范,首先将万事万物当成对象来理解,他们都有各自的特征和行为方式,映射到程序设计层面就是每个对象都有表示各自的属性和功能,在我们处理问题时,建立不同的对象,不是为了实现一个步骤,而是描述一个事物在处理问题过程中的特性和行为。问题的解决通过对象间的交互完成。

    • 面向过程思想理解:着眼于每一个具体步骤,用函数和方法一步步将问题解决,整个流程串联起来实现具体功能。

    • 面向对象和面向过程的区别:
      面向过程 :面向过程性能比面向对象高。 因为类调用时需要实例化,开销比较大,比较消耗资源,所以当性能是最重要的考量因素的时候,比如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发。但是,面向过程没有面向对象易维护、易复用、易扩展。
      面向对象 :面向对象易维护、易复用、易扩展。 因为面向对象有封装、继承、多态性的特性,所以可以设计出低耦合的系统,使系统更加灵活、更加易于维护。但是,面向对象性能比面向过程低。
      另一个维度,当程序比较简单时面向过程设计更加简洁清晰,效率也高,但当功能越来越复杂,面向过程设计就愈发臃肿难以维护,所以面向对象思想更适合大型程序设计。

    • 类和对象的区别
      类是一组属性和行为的集合,是一个抽象的概念;
      对象是该类事物的具体表现形式,是实体。

    java三大特性(???修改)

    1.封装, 将对象的数据和行为整合在一起,对外部只暴露方法接口,隐藏具体实现,只要方法不变,对象内部数据如何变化并不直接影响其他类
    2.继承,拓展一个已有的类时,拓展后的新类具有所拓展类的全部属性和方法,在新类中,只需要提供适用于这个新类的新方法和数据域即可
    3.多态,同一个对象的引用可以指向不同的类型,即父类接口可以指向子类对象,这样可以提高代码的拓展性,但父类引用不能指向子类的特有内容,也不能用子类引用指向父类对象。

    • java对象的内存图
    构造器

    java中使用构造器创建对象并初始化部分状态;

    补充的tip:
    1.一个对象变量并没有真正包含一个对象,而仅仅是引用一个对象
    2.对于包含多个文件的java程序编译,可以使用两个方法:
    javac Classname*.java 通配符方法;
    javac Classname.java 不会显示地编译该类使用的其他类文件,但是当编译器发现并没有需要的class文件时候,就会自动搜索并编译缺少的类文件。此外,编译器如果发现现有的.java文件比已有的.class文件新,就会自动重新编译这个文件。

    构造器基本特性:

    • 与类同名
    • 每个类有一个以上的构造器
    • 构造器可以有0,1或者多个参数
    • 构造器没有返回值和返回值类型,连void也没有
    • 总是伴随着new一起调用

    注意事项:

    • 系统会自动提供一个默认修饰符的无参构造方法,如果我们给了构造方法,无论有参数还是无参数,系统都不会默认提供了。
      从编码规范角度看,建议坚持至少创建无参构造器
    • 创建对象的时内存过程:
    class Student {
        private String name = "Franz";
        private int age = 24;
        public Student() {
            name = "Leo";
            age = 25;    
        }
    }
    
    class StudentDemo {
    public static void main(String[] orgs) {
        Student stu = new Student();
    }
    
    }
    

    class文件加载到方法区,然后main方法进入栈区,创建指向对象的局部变量,然后在堆区创建新对象,其中的成员变量先被初始化为默认值,紧接着被赋予等号后初始值,然后才进入构造方法,被初始化为新的值,然后把堆内存的地址值赋值给stu变量。

    • 有时候就算按常规设置了私有域域和共有域访问器方法,仍然可能破坏封装性,如
    class Employee {
        private Date hireDay;
        public Date getHireDay() {
            return hireDay;//这样外部获得该hireDay之后会调用Date额setTime方法改变该date
    }
    }
    

    这种情况我们应该先对对象克隆,对象克隆是指存放在另一个位置上的对象副本。如果需要返回一个可变数据域的拷贝,就应该是使用clone.下面是修改后的代码

    public Date getHireDay() {
        return hireDay.clone();
    }
    
    • 被final标记的域必须在声明时初始化或者在构造器中初始化
    • 构造器不能被重写,因为子类不能继承父类的私有域和构造方法。但是构造器可以重载。

    重载和重写的关系:
    重载overload:发生在编译时。在一个类里面,方法名字相同,参数类型或个数或顺序不同,则被视为重载,这是判断是否重载的核心。返回值类型可能不同,访问修饰符可能不同,检查异常范围可能不同。
    重载严格意义上并不属于多态,重载的具体实现是:编译器根据不同的参数表,对同名函数的名称做修饰,然后这些同名函数就变成了不同的函数。对重载函数的调用,在编译期间就已经确定了,是静态的(注意!是静态的),因此,重载和多态无关。

    重写override:发生在运行时。重写是子类对父类被允许访问的方法实现过程进行重新编写,函数名和参数列表必须和父类方法相同。返回值范围小于等于父类,访问权限必须大于等于父类,抛出的异常范围小于等于父类,final、static声明的方法不能被重写,构造方法不能被重写,private声明的方法不能被重写。
    真正和多态相关的是重写,当子类重写了父类中的函数后,父类的 指针,根据赋值给它不同的子类对象指针,动态的调用属于子类的该函数,这样在编译期间是无法确定的,只有在运行期间,才会把动态链接转变为直接引用
    同名同签名的方法,父类方法如果加上了static修饰符,子类也应该加上static修饰符,这由于不涉及对象算不上重写,至于为什么?????

    • 当一个变量被用来表示一个类的属性时候,才被规定为成员变量。变量的使用应该遵循影响范围越小越好原则,为了能被及时回收,防止夜长梦多。
    • 子父类构造器的关系?
    • 类加载过程,关于构造器、成员变量、静态代码块、代码块等?
    静态域和静态方法

    用于修饰类中被所有对象共享的变量或方法,它随着类的加载而加载,优先于对象存在。所以main方法是静态的,因为它被虚拟机调用,不需要创建对象。
    注意点:

    • 由于静态域和方法不单独属于任何对象,所以在静态方法中不能有this关键字,静态方法只能访问静态的成员变量或方法。
    • 静态成员变量和方法存在方法区的静态区(成员变量存储于堆内存),当在堆中创建对象时候,不同对象中的静态引用指向同一个静态区的数据。
    • 静态变量的生命周期同步于类,成员变量的生命周期同步于对象

    关于main方法的补充:
    public修饰符,因为需要被jvm直接调用,访问权限要最大;
    static,因为不需要创建对象
    void,方法的返回值是给调用者,jvm不需要main方法的调用值
    string[] args,命令行参数,输入格式为java classname command line parameters, 一般我们没输入这个参数,所以系统接收的是一个长度为0的字符串数组。

    补充,java方法参数是值传递还是引用传递的问题

    首先看基本数据类型参数
    public static void rise(double salary) {
            salary = salary * 3;
        }
    
        public static void main(String[] args) {
            double salary = 100;
            rise(salary);
            System.out.println(salary);
        }
    //输出为100
    
    然后看对象引用作为参数时成员变量的变化
    public static void growUp(Student student) {
            student.setAge(student.getAge() + 1);
        }
    
        public static void main(String[] args) {
            Student student = new Student(15);
            System.out.println(student.getAge());
            growUp(student);
            System.out.println(student.getAge());
        }
    //输出为15.0,16.0.
    
    再看最后一种情况
     public static void swamp(Student a, Student b) {
            Student temp = a;
            a = b;
            b = temp;
            System.out.println(a.getAge()+"   "+b.getAge());
        }
    
        public static void main(String[] args) {
            Student a = new Student(15.5);
            Student b = new Student(16.5);
            swamp(a,b);
            System.out.println(a.getAge()+"   "+b.getAge());
        }
    //输出结果
    16.5   15.5
    15.5   16.5
    

    结论一:方法不能修改基本数据类型的参数;
    结论二:传入对象引用作为参数时能够改变对象的状态,因为方法参数和传入的对象引用同时指向同一个对象;
    结论三:传入对象引用并不能被改变指向
    根本结论:java语言是按值调用,方法得到的是所有参数值的一个拷贝,方法不能修改传递给它的任何参数变量的内容。

    补充,java内存图解

    访问其他包的共有类两种方法,类前加前缀或者导包;

    • 注意号只表示导入了单个包中的所有类,不能使用import java.或者import java..表示导入了以java为前缀的所有包。
    • 当有重名的类时,如同时import了java.util.和java.sql.这就需要再加句import java.util.Date表示使用的是该包下的Date,如果两个都想要,那么在类前缀前加包名。
    • 静态导入,import static java.lang.System.*,这样就能在程序中使用System类的静态内容,如out.println();此外,还可以导入特定的方法或方法域,import static java.lang.System.out,这个用的很少。
    • 如果类文件没有指定package语句,就会被放到一个默认包中
    • 编译器编译java文件,而解释器加载.class文件。使用编译命令时需要指定完整的包名,如javac com/***/****/Student.java,此时编译器还会自动查找同类名下使用到的其他文件并编译。
    代码块
    • 局部代码块 在方法中出现,限定变量声明周期,及时释放无用变量,提高内存利用率
    • 构造代码块 在类中方法和构造函数之外出现,用于对每个对象进行与构造方法无关的初始化,每次创建对象都会执行,并且在构造方法前执行。
    • 静态代码块 与之前两种形式上区别就是多了个static,对类进行初始化,在所有代码块中最先执行,但只执行一次。在main方法所在的类中,该类的静态代码块仍然领先于main方法执行,所以方法加载是在类加载之后的。

    相关文章

      网友评论

        本文标题:java类的基本构成

        本文链接:https://www.haomeiwen.com/subject/hykksqtx.html