• java重点知识


    一、java基本知识点

           java是由SUN公司在1995年推出的,在2009年SUN公司又被甲骨文公司收购,所以甲骨文公司获得java版权。其底层是由C语言写的,java分为三个体系:

    • JavaSE,即Java Platform Standard Edition,java平台标准版。
    • JavaEE,即Java Platform Enterprise Edition,java平台企业版。
    • JavaME,即Java Platform Micro Edition,java平台微型版。

      其中JavaSE标准版更多的是基础语法,而JavaEE是用于企业的,扩展了其他的一些功能,可以说JavaSE是JavaEE的子集。而JavaME用的很少,不做讨论。

      

           另外,java有下面的特性比较重要:

    • 简单。 其语法和C++接近,但是没有用操作符重载、多继承、指针等比较复杂的概念,并且提供了自动的垃圾收集机制,和JavaScript类似。
    • 面向对象。 java最大的特点就是面向对象。提供了类、接口、继承等概念。
    • 分布式语言。支持Internet应用的开发,在基本的Java应用编程接口中有一个应用编程接口(java net)。
    • 中立的体系结构。java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后缀为class的文件),然后可以在实现这个java平台的任何系统中运行。
    • 支持多线程。和JavaScript的单线程不同,java语言支持多线程,通过Thread类来创建。

      

    二、java开发工具以及安装配置

     

    (1)jvm、jre、jdk、sdk、eclipse区别和联系。

       JDK(Java Development Kit)是Java语言的开发工具包(SDK)。在JDK的安装目录下有一个jre目录,里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和lib合起来就成为jre。

       JRE(Java Runtime Environment)即java运行环境,包含JVM标准实现以及Java核心类库。JRE是Java的运行环境,并不是一个开发环境,所以没有包含任何开发工具(如编译器和调试器)。

       JVM(Java VIrtual Machine)即java虚拟机,JVM是一种用于计算设备的规范,是一个虚构出来的计算机,是通过在实际的计算机上仿真模拟各种计算机功能来实现的。                                         

            (参考自文章:https://blog.csdn.net/songkai320/article/details/51819046)

       如上,所以JDK是整个Java的核心,而JRE是Java程序必须的环境的集合,包含了JVM标准实现和Java核心类库。JVM是整个java实现跨平台的最核心的部分,能够运行以Java语言写的程序。

       而eclipse是方便我们写java程序的开发工具,它不是必须的,就像我们写前端html页面,你可以使用记事本来写,当然也可以使用sublime这种开发工具来写。

    (2)java开发环境配置

      我们可以在oracle公司网站上下载jdk,进入之后选择与本机操作系统对应的jdk文件即可,且在安装jdk的同时会提示安装jre,直接安装即可。

         在cmd中运行 java -version、java、javac几个命令,出现了相关信息,没有报错,就说明环境变量配置成功。

      我在安装java环境的时候,首先安装到了D盘新建的Java中,然后中间又在安装什么没有看清楚,安装到了c盘program files下面的java中。安装完成之后cmd中输入java --version是可以成功的,输入java也显示了很多内容,但是输入javac时不能正确识别,然后,我将 D:javain 也加入了环境变量,就都可以识别了。如下所示:

           

       如上,如果javac和java两者都成功运行,那么基本的java环境就搭好了,如果想要运行文件,只需要用一个记事本写java程序然后通过命令行运行即可。

      工具下载可以在网站 https://down.eeyes.net 上下载,更加正规,不存在有病毒的可能。

     (3)JAVA开发工具

      Eclipse是免费开源的java IDE,是绝大多数开发者的选择,选择Eclipse IDE for Java Developers即可。其他的编辑器也很多,比如notepad++以及netbeans等。这里我们还是推荐使用Eclipse。

      而如果要开发安卓app,一般使用的是 Android Studio,因为相对来说Eclipse更加臃肿,所以开发安卓推荐 Android Studio。

      

       

    三、第一个例子

      我们随意打开一个编辑器,创建FOO.java文件,文件中的代码如下所示:

    public class FOO {
        public static void main(String[] args) {
            System.out.println("hello world!");
        }
    }

      然后因为我们这里还没有使用IDE(如eclipse),所以可以使用命令行编译运行,如下:

          

       即我们首先使用javac命令(即java compile)进行编译文件,然后使用java命令来执行文件。

       注意:类名必须和文件名保持一致,即该文件名必须为FOO.java。

      接下来,我们使用eclipse创建一个java程序,如下:

      先创建一个java project:

      

      然后我们创建一个class:

      然后在创建class时,需要右键src,package就自动创建好了,然后结果如下:

          

      即首先创建一个foo工程,在src文件并列的有JRE System Library,然后在src下创建一个foo包,这个包中创建一个Foo.java类即可,类下代码如下:

    package foo;
    
    public class FOO {
        public static void main (String[] args) {
            System.out.println("wayne");
        } 
    }

      然后点击运行,如下:

      最后结果如下:

      即在console控制台中打印出了最终结果。

    四、java基础语法

    (1)基础部分

    • 大小写敏感。
    • 类名首字母要大写,且类名使用的是大驼峰式写法。
    • 方法名必须要以小写字母开头。
    • 源文件名必须要和类名相同,后缀是java,如果文件名和类名不同则会导致编译错误。
    • 主文件入口所有的Java程序都必须由 public static void main(String []args)方法开始执行

      

     (2)变量

      java中的变量有局部变量、类变量(静态变量)以及成员变量(非静态变量)。其中局部变量就是一般函数中的变量,而静态变量是类中的变量,但是静态变量的特点是用static修饰了,且不需要通过实例来引用这个变量,而非静态变量是类中没有使用static修饰的变量,并且非静态变量必须要通过实例来引用。

     

     (3)关键字

      java中的关键词和其他语言关键字也都是大同小异,比如private、protected、public、class、extends、interface、static、break、for、case、do、try、void、goto等等等等。

     (4)注释

      注释和JavaScript一样,使用 // 作为单行注释,使用 / * */作为多行注释。当然,这些注释行和所有的空白行都会被java编译器在编译的过程中直接忽略。

    (5)接口

      在java中,接口可以理解为对象之间相互通信的协议。接口在继承中扮演着非常重要的角色,接口只定义派生要用到的方法,但是方法的具体实现完全取决于派生类。

    (6)java源程序与编译型运行区别

             

    • 编译型语言。如c/c++,他们通过编译器直接编译为exe可执行文件,然后在运行的时候就可以直接运行,而不需要解释,所以速度很快。
    • 解释型语言。如java、JavaScript,java写完之后编译为class文件,然后这个文件是不能直接运行的,还需要再运行的时候边解释边运行,所以速度较慢。

      

    五、java对象和类

      面向对象的语言不只是java,还有c++、python之类的,所以在理解起来都是没有问题的,大同小异。比如对象是类的一个实例,它有状态(属性)和行为(方法),而类是一个模板,这个模板它描述了一类对象的行为和状态。在我们创建第一个java程序时,我们就使用到了类,即public class 类名 {} 。

      而java中的变量(这里不是类的变量)有多种,即局部变量、成员变量、类变量。如在方法中定义的变量,就是局部变量,因为它会在方法执行完成之后立即被销毁,这就是局部变量;而成员变量是定义在类中、方法体之外的变量。这种变量在创建对象的时候实例化,它可以被类中方法、构造方法和特定类的语句块访问; 而类变量也是生命在类中的,方法体之外,但必须声明为static类型,且不是被实例访问,而是类访问的。

       而java中的构造方法和c++中的构造函数是类似的,他们都是为了更加方便的构造实例,并且两者的构造函数如果开发者没有定义就会自动提供一个默认的构造函数 ,且构造方法和类的名称必须要同名,一个类可以有多个构造方法。

       如下所示,创建一个Puppy类,这个类中含有两个构造方法:

    public class Puppy{
        public Puppy(){
        }
     
        public Puppy(String name){
            // 这个构造器仅有一个参数:name
        }
    }

      而如下所示的程序就可以创建一个实例:

    public class FOO {
        public FOO(String name) {
            // 构造方法,创建一个实例时输出其名称
            System.out.println("create a new object:" + name);
        }
        public static void main(String[] args) {
            FOO foo = new FOO("wayne");
        } 
    }   

      但是在运行时时会发生编译错误,即无法正常解码,我们使用 -encoding UTF-8 的编码方式即可,如下所示:

    PS C:UsersAdministratorDesktop> javac -encoding UTF-8 FOO.java
    PS C:UsersAdministratorDesktop> java FOO
    create a new object:wayne

      这样,我们就可以得到争取的结果了。

      另外,如果我们希望访问属性和方法也可以通过下面的方式进行访问:

    public class FOO {
        public FOO(String name) {
            // 构造方法,创建一个实例时输出其名称
            System.out.println("create a new object:" + name);
        }
        int fooAge;
        public void setAge(int age) {
            fooAge = age;
        }
        public int getAge() {
            System.out.println("the age is:" + fooAge);
            return fooAge;
        }
        public static void main(String[] args) {
            FOO foo = new FOO("wayne");
            foo.setAge(22);
            foo.getAge();
        } 
    }   

      如上所示,通过int Age就可以创建一个实例变量,方法也是类似的,最后我们在public static void main函数中执行主要的逻辑,通过foo.setAge和foo.getAge来调用实例方法。最后结果如下:

    PS C:UsersAdministratorDesktop> javac -encoding UTF-8 FOO.java
    PS C:UsersAdministratorDesktop> java FOO
    create a new object:wayne
    the age is:22

      ok,到这里,我们就对java中基本的类、实例、属性、方法等有一个基本的了解了。

      

    六、其他相关规则(源文件、包)

      即我们在一个.java这样的源文件中是要遵循相应的规则的,比如说一个源文件只能有一个public类但是一个源文件可以有多个非public类、源文件的名称应该和publick类的类名保持一致、如果一个类定义在了某个包中那么package语句应该在源文件的首行、而如果源文件包含import语句,那么应该放在package语句和类定义之间;如果没有package语句,那么import语句应该放在源文件中最前面、import语句和package语句对源文件中定义的所有类都有效。

      java包的主要作用是对类和接口进行分类,当开发java程序时,可能编写成百上千的类,因此很有必要对类和接口进行分类。 

      在java中,如果给出一个完整的限定名,包括包名、类名,那么java编译器就可以很容易地定位到源代码或者类了,而import语句就是用来提供一个合理的路径,使得编译器可以找到某个类

    package和import的区别:

      两者是互逆的过程,如package freedom.bean语句的作用是将当前的类(class文件)打包到这个freedom.bean包中; 而 import freedom.bean.* 就是把freedom.bean这个包中的所有类都引入,这样就可以使用了,比如我们是可以引用到之前package freedom.bean的类的。

      又如,我们通过import java.io.*就可以导入输入输出相关的所有类。  

      下面,我们通过一个例子来进行进一步的讲解,这个例子中,我们创建Employee和Employee Test两个类。

      首先,我们创建Employee.java文件,如下:

    import java.io.*;
     
    public class Employee{
       String name;
       int age;
       String designation;
       double salary;
       // Employee 类的构造器
       public Employee(String name){
          this.name = name;
       }
       // 设置age的值
       public void empAge(int empAge){
          age =  empAge;
       }
       /* 设置designation的值*/
       public void empDesignation(String empDesig){
          designation = empDesig;
       }
       /* 设置salary的值*/
       public void empSalary(double empSalary){
          salary = empSalary;
       }
       /* 打印信息 */
       public void printEmployee(){
          System.out.println("名字:"+ name );
          System.out.println("年龄:" + age );
          System.out.println("职位:" + designation );
          System.out.println("薪水:" + salary);
       }
    }

      然后,创建EmployeeTest.java如下:

    import java.io.*;
    public class EmployeeTest{
     
       public static void main(String args[]){
          /* 使用构造器创建两个对象 */
          Employee empOne = new Employee("RUNOOB1");
          Employee empTwo = new Employee("RUNOOB2");
     
          // 调用这两个对象的成员方法
          empOne.empAge(26);
          empOne.empDesignation("高级程序员");
          empOne.empSalary(1000);
          empOne.printEmployee();
     
          empTwo.empAge(21);
          empTwo.empDesignation("菜鸟程序员");
          empTwo.empSalary(500);
          empTwo.printEmployee();
       }
    }  

      注意:前两个文件要放在同一个文件夹下。

      最后,我们直接运行即可,最终结果如下:

    PS C:UsersAdministratorDesktop> javac -encoding UTF-8 EmployeeTest.java
    PS C:UsersAdministratorDesktop> java EmployeeTest
    名字:RUNOOB1
    年龄:26
    职位:高级程序员
    薪水:1000.0
    名字:RUNOOB2
    年龄:21
    职位:菜鸟程序员
    薪水:500.0

      所以,我们可以发现,创建了Employee.java这个类之后,我们并不需要package将之打包,也不需要在EmployeeTest.java中使用import引用,而是如果两者在同一个文件夹下,那么就可以直接在一个文件中调用另外一个类。并且,要通过上述的运行,我们即使不使用 import java.io.* 也是可以正常执行的。但是,如果我们没有将两者放在同一个文件夹下,就会出现问题,而不能正常执行。

      

    七、java基本数据类型

      java中也分为了两种数据类型,一种是内置数据类型,另外一种是引用数据类型,这个和JavaScript是一样的。

      但js中的基本数据类型有5种,而java中的基本数据类型却有8种(四个整数型、两个浮点型、一种字符类型、一种布尔型)。

    • byte数据类型。它是8位、有符号的、以二进制补码表示的整数,最小值为-128,最大值为127,默认值为0. byte类型占用的空间只有int类型的四分之一。
    • short数据类型。它是16位、有符号的、以二进制补码表示的整数,最小值是-32768(-2^15),最大值是32767(2^15 - 1),short类型和byte类型一样都很节省空间,因为short变量是int变量所占空间的二分之一。它的默认值也是0.
    • int数据类型。它是32位、有符号的以二进制补码表示的整数,最小值为-2^31,最大值是2^31 - 1,一般整型变量默认就是int类型,默认值为0。
    • long数据类型。它是64位、有符号的以二进制补码表示的整数,最小值为-2^63,最大值为2^63 - 1,这种类型主要使用在需要比较大整数的系统上。默认值为0L。比如 long a = 100000L。
    • float数据类型。它是单精度、32位、符合IEEE 754标准的浮点数。它在储存大型浮点数组的时候可以节省内存空间,默认值为0.0f,它不能用来表示精确的值,如货币。 如float f1 = 234.5f。
    • double数据类型。它是双精度、64位、符合IEEE 754标准的浮点数。浮点数的默认类型就是double类型。它同样不能表示精确的值,如货币。默认值是0.0d。如double d1 = 123.4。
    • boolean数据类型。它表示一位的信息,只有两个取值:true和false。 这种类型只作为记录true/false情况,默认值是false。比如boolean one = true。
    • char类型。char类型是一个单一的16位的Unicode字符,最小值是 u0000(即为0), 最大值是 uffff(即为65535),char数据类型可以存储任何字符,比如char letter = 'A';。

      如上,就是四类8种基本数据类型了。在上面的详细介绍中,有其最大最小值的限制,而实际上,我们根本就不不要记住,而是通过MIN_VALUE和MAX_VALUE就可以获取到了。如下所示:

    public class FOO {
        public static void main (String[] args) {
            System.out.println("基本类型: byte二进制位数: " + Byte.SIZE);
            System.out.println("包装类: java.lang.Byte");
            System.out.println("最大值: Byte.MIN_VALUE=" + Byte.MIN_VALUE);
            System.out.println("最小值: Byte.MAX_VALUE=" + Byte.MAX_VALUE );
            System.out.println();
    
            System.out.println("基本类型: int二进制位数: " + Integer.SIZE);
            System.out.println("包装类: java.lang.Integer");
            System.out.println("最大值: Integer.MIN_VALUE=" + Integer.MIN_VALUE);
            System.out.println("最小值: Integer.MAX_VALUE=" + Integer.MAX_VALUE );
            System.out.println();
    
            
            System.out.println("基本类型: char二进制位数: " + Character.SIZE);
            System.out.println("包装类: java.lang.Character");
            System.out.println("最大值: Character.MIN_VALUE=" + (int)Character.MIN_VALUE);
            System.out.println("最小值: Character.MAX_VALUE=" + (int)Character.MAX_VALUE );
            System.out.println();
        }
    }

      即我们可以通过如上的方式获取到java中基本数据类型的范围,结果如下:

    基本类型: byte二进制位数: 8
    包装类: java.lang.Byte
    最大值: Byte.MIN_VALUE=-128
    最小值: Byte.MAX_VALUE=127
    
    基本类型: int二进制位数: 32
    包装类: java.lang.Integer
    最大值: Integer.MIN_VALUE=-2147483648
    最小值: Integer.MAX_VALUE=2147483647
    
    基本类型: char二进制位数: 16
    包装类: java.lang.Character
    最大值: Character.MIN_VALUE=0
    最小值: Character.MAX_VALUE=65535

      上面说了8种都是java中的基本数据类型,下面是java中的引用类型。java中的应用类型非常类似于c/c++中的指针,引用类型指向一个对象,指向对象的变量是引用变量,这些变量声明时被指定为一个特定的类型,比如Employee、Puppy等。注意:对象、数组都是引用类型,所有引用类型的默认值都是null,一个引用变量可以用来引用任何与之兼容的类型。如Site site = new Site("wayne");

      

      java常量。java常量在程序运行中是不能被修改的,常量的声明方式和变量类似,使用final关键字,如下:

    final double PI = 3.1435926;

      一般,这个常量的大小写没有限制,但是最好使用大写,便于观察。

      在java中,字符串常量和字符常量都可以包含任何Unicode字符,例如:

    char a = 'u0001';
    String a = "u0001";

      java语言支持一些特殊的转义字符序列。

    八、java类型转换

       整型、常量、字符型数据可以混合运算,运算中,不同的数据类型先转化为同一数据类型,然后进行运算。

       转换由低级到高级(而如果从高级到低级转换,就会导致精度丢失了),如下:

    低  --------------------------------------->byte,short,char—> int —> long—> float —> double 

        注意,转换过程中也是要遵循一定的规则的:

    • 不能对boolean类型进行类型转换。
    • 不能吧对象类型转换为不想关类的对象。
    • 在把容量大的类型转换为容量小的类型时,必须使用强制类型转换。
    • 转换过程中可能导致溢出或者损失精度,如下:
    int i =128;   
    byte b = (byte)i;

      byte类型最大值为127,所以,int类型强制转化为byte类型时,值128时就会导致溢出。

    • 浮点数到整数的转化是通过舍弃小数得到的,而不是四舍五入,如(int)23.7 == 23; 。

      强制类型转换的条件是转换的数据类型必须是兼容的,比如:

    int i = 123;
    byte j = (byte)i;

      这里就将int类型的i强制转化为了byte类型的j了。

    九、java中的Number类和Math类

      在java中,我们可能常常会用到byte、int、long、double等内置数据类型,但是,在实际开发中,我们可能经常会用到它们的对象,因为对象上封装了很多方法,可以方便我们调用,而所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类Number的子类,而Number类是属于java.lang包的。    

         

      如下所示:

    public class Test {
        public static void main(String[] args) {
            Integer num = 5;
            System.out.println(num);
        }
    }

      编译执行之后就会输出5。这只是一个简单的例子,如果真的只能这么用,还不如直接用int,所以啊,其实Interger包括其他继承自Number类的类都有很多方法可以调用,后面会讲到。

      

      另外,Math类也是在数值计算中常常会用到的,java中的Math包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数。如下所示:

    public class Test {
        public static void main(String[] args) {
            System.out.println("90度的正弦值: " + Math.sin(Math.PI/2));
            System.out.println("0度的余弦值: " + Math.cos(0));
            System.out.println("求2的3次方: " + Math.pow(2, 3));
        }
    }

      最终结果如下所示:

    90度的正弦值: 1.0
    0度的余弦值: 1.0
    求2的3次方: 8.0

      

      而下面是Number和Math的一些类方法:

    • xxxValue()  - 如byteValue()可以将Number类型的值转化为基本数据类型的byte类型。
    • compareTo() - 将number对象与参数进行比较。
    • equals() - 判断number对象与参数是否相等。
    • valueOf() - 返回一个Number对象指定的内置数据类型。
    • toString() - 以字符串的形式返回。
    • parseInt() - 将字符串转化为int类型。
    • abs() - 返回参数的绝对值。
    • ceil() - 返回大于等于给定参数的最小整数。
    • floor() - 返回小于等于给定参数的最大整数。
    • rint() - 返回与参数最接近的整数,返回类型为double。
    • min() - 返回两个参数中的最小值。
    • max() - 返回两个参数中的最大值。
    • random() - 返回一个随机数。

     

    十、java中的String类

      字符串广泛应用在java编程中,在java中字符串属于对象,java提供了String类来创建和操作字符串。

      如下我们可以创建String对象:

    public class Test {
        public static void main(String[] args) {
            String c = "wayne-zhu";
            String b = new String("hedy-he");
            System.out.println(c); // wayne-zhu
            System.out.println(b); // hedy-he
        }
    }

      上面的例子中演示了两种创建String实例的方法,都是正确的。

      而使用String,是为了使用String类的方法,如下:

    public class Test {
        public static void main(String[] args) {
            String c = "wayne-zhu";
            String b = new String("hedy-he");
            int cLen = c.length();
            System.out.println("cLen: " + cLen); // clen: 9
    
            String d = c.concat(b);
            System.out.println("d: " + d); // d: wayne-zhuhedy-he
    
            String fs;
            fs = String.format("浮点型变量的值为:%f" + ", 整型变量的值为: %d" + ", 字符型变量的值为: %s", 0.618, 666, "wayne");
            System.out.println(fs);
        }
    }

      最终结果如下所示:

    cLen: 9
    d: wayne-zhuhedy-he
    浮点型变量的值为:0.618000, 整型变量的值为: 666, 字符型变量的值为: wayne

      另外,String还有其他很多方法:

    • char charAt(int index)返回指定索引处的char值。
    • int compareTo(Object o)把这个字符创和另外一个对象比较,返回的是ASCII差值。
    • int compareTo(String anotherString)按照字典顺序比较两个字符串
    • int compareToIgnoreCase(String str)按照字典顺序比较,不考虑大小写
    • String concat(String str)将指定字符串连接到此字符串的结尾。
    • int indexOf(int ch)返回指定字符串中第一次出现处的索引。

    十一、java数组

      数组在任何编程语言中都是存在的,它用来存储固定大小的同类型元素,这里主要介绍java数组的声明、创建、初始化。

    double[] myList; // 首选的方法
    
    double myList[];

      如上所示,我们声明数组有两种方法,第一种是推荐的方法,第二种也可以,但是不推荐。

      

           上面是声明的过程,但是创建数组要用下面的方法:

    double[] myList = new double[10];

      这里,我们创建了myList数组,且长度为10。

      

      当然,我们可以直接赋值,如下所示:

    double[] myList = {1.0, 131.1, 2.3, 6.3};

      

      另外,数组有for循环可以调用,如果要单独访问到某个元素,可以使用下标进行访问,如下所示:

    public class Test {
        public static void main(String[] args) {
            double[] myList = {1.1, 1.2, 1.3, 1.4};
            System.out.println("第一个元素: " + myList[0]);
            for (double element: myList) {
                System.out.println(element);
            }
        }
    }

      最终结果如下所示:

    第一个元素: 1.1
    1.1
    1.2
    1.3
    1.4

      

      另外,数组也可以作为参数被传递,也可以是一个函数的返回值。

    十二、java方法

      在java中,我们之前用到的最多的时System.out.println(),其中:

    • println()就是一个方法。
    • out是对象。
    • System是类。  

      即println()是System类下的out对象的方法。

      方法其实就是函数,在JavaScript、c++等语言中都是一样的,它可以使得程序变得简洁而清晰、有利于程序维护、可以提高程序开发的效率、提高了代码的重用性。

      需要注意的是,和JavaScript不同,java对方法的命名有一定的要求:即方法的名字的第一个单词应以小写字母开头,后面的单词则用大写字母开头,不使用连接符,例如addPerson; 下划线可能出现在JUnit测试方法名称用以分隔名称的逻辑组件,如test<MethodUnderTest>_<state>,即testPop_emptyStack。

       方法的定义如下:

    修饰符 返回值类型 方法名(参数类型 参数名) {
       ...
       方法体
       ...
       return 返回值;
    }

      方法中包含了一个方法头和一个方法体,下面是一个方法的所有部分:

    • 修饰符: 这是可选的,即告诉编译器如何调用该方法,如public static 等。
    • 返回值类型: 方法可能会返回值。 如int double等等,如果没有返回值,那么就用void。
    • 方法名: 即方法的实际名称。
    • 参数类型:参数是可选的,方法可以不传递任何参数,但如果传递,则需要说明其类型、顺序以及参数的个数。
    • 方法体: 即具体的语句,来定义该方法的功能。

      

       java中的方法根据返回值或者参数的不同可以实现重载,如下所示:

    public class Test {
        public static void main(String[] args) {
            int x1 = 2;
            int x2 = 5;
            System.out.println(add(x1, x2));
    
            double y1 = 1.5;
            double y2 = 2.2;
            System.out.println(add(y1, y2));
        }
        public static int add(int a, int b) {
            System.out.println("返回一个int值");
            return a + b;
        }
        public static double add(double a, double b) {
            System.out.println("返回一个double值");
            return a + b;
        }
    }

      最终的结果如下所示:

    返回一个int值
    7
    返回一个double值
    3.7

      这样,我们就完成了java方法的重载。 注意,上面函数使用public表示该方法可以被外部访问,使用static之后,如果这个方法在这个类之外被调用,可以直接Test.add调用,如果没有static修饰符,就要先创建一个Test的实例,然后通过实例来调用。

      既然,这里讲到了方法,那么其实我们每次在写最基本的java程序的时候 public static void main 就是一个方法了,并且每次通过 "java 文件名" 来调用的时候,就是调用的这个main函数,那么如果给这个main函数传递参数呢?其实,这时只要通过命令行来传递参数就可以了,如下:

    public class Test {
        public static void main(String[] args) {
            for (int i = 0; i < args.length; i++) {
                System.out.println("args[" + i + "]: " + args[i]);
            }
        }
    }

      即我们在命令行中输入的就是这里的agrs,其实根据之前学的数组,可以将main函数中的参数写成(String args[])也是可以的。

      最终的结果如下:

          

       

        

    十三、Java流(Stream)、文件(File)和IO

      Java.io包括几乎所有的操作输入、输出所需要的类,所有这些类代表了输入源和输出目标,一个流可以理解为一个数据的序列,输入流表示从一个源读取数据,输出流表示向一个目标写数据,且Java为I/O提供了强大、灵活的支持,使其广泛地应用到文件传输和网络编程中。 

      

    十四、java面向对象

      java是面向对象的,自然有继承的概念,java中使用extends表示子类继承父类,继承之后,子类拥有父类非private的属性、方法; 子类也可以拥有自己的属性的方法,即子类可以对父类进行扩展;子类可以用自己的方式实现父类的方法;java可以单继承也可以多继承;

      java中所有的类都是继承与java.lang.Object。java中,类的继承是单一继承,即一个子类只能有一个父类,即extends只能继承一个类。

      而如果使用implements关键字可以变相的使java具有多继承的特性,使用范围为类继承接口的情况,如下:

    public interface A {
        public void eat();
        public void sleep();
    }
     
    public interface B {
        public void show();
    }
     
    public class C implements A,B {
    }

      这样,C就同时继承了A和B。 

      在java中,我们还常常见到super和this关键字。其中:

    • super关键字用来实现对父类成员的访问,用来引用当前对象的父类
    • this关键字用来指向自己的引用
    class Animal {
      void eat() {
        System.out.println("animal : eat");
      }
    }
     
    class Dog extends Animal {
      void eat() {
        System.out.println("dog : eat");
      }
      void eatTest() {
        this.eat();   // this 调用自己的方法
        super.eat();  // super 调用父类方法
      }
    }
     
    public class Test {
      public static void main(String[] args) {
        Animal a = new Animal();
        a.eat();
        Dog d = new Dog();
        d.eatTest();
      }
    }

      最终结果如下:

    animal : eat
    dog : eat
    animal : eat

      

      另外,在java中,final关键字表示可以把类定义为不能继承的,即最终类; 或者用于修饰方法,该方法不能被子类重写。

      

      重写(Override) - 即子类对父类的允许访问的方法的实现过程进行重写,返回值和形参都不能改变,即外壳不变,核心重写。它的好处是子类可以根据需要,定义属于自己的行为,也就是说子类能够根据需要实现父类的方法。 如下:

    class Animal{
       public void move(){
          System.out.println("动物可以移动");
       }
    }
     
    class Dog extends Animal{
       public void move(){
          System.out.println("狗可以跑和走");
       }
    }
     
    public class TestDog{
       public static void main(String args[]){
          Animal a = new Animal(); // Animal 对象
          Animal b = new Dog(); // Dog 对象
     
          a.move();// 执行 Animal 类的方法
     
          b.move();//执行 Dog 类的方法
       }
    }

      最后结果如下:

    动物可以移动
    狗可以跑和走

      而如果子类希望调用父类的被重写方法时,就要使用super关键字了,这样,就可以调用父类方法。

      

      刚刚我们说的是重写(override),即在子类中重写(覆盖)父类的方法。

      这里我们要说的是重载(overload),即在一个类里面,方法名字相同,而参数不同,返回类型可以相同也可以不同 。但参数必须有所不同!且最常见的其实就是构造器的重载。被重载的方法必须改变参数列表(参数个数或者类型不一样),但是其返回类型可以修改,并且访问修饰符可以修改。如下所示:

    package jicheng;
    
    public class Jicheng {
        public int test(){
            System.out.println("fa");
            return 1;
        }
        public void test(int a) {
            System.out.println("test2");
        }
        public static void main(String[] args) {
            Jicheng foo = new Jicheng();
            foo.test();
            foo.test(1);
        }
    }

      多态。 这个概念在生活中可以理解为比如按下up键,在word中是移动到上一行;在游戏中,是前进;在网页中,是向上滑动; 即同一个事件发生在不同的对象上会产生不同的结果。
    又比如你打印一个东西,按下打印键之后,在彩色打印机上打印出的是彩色、而在黑白打印机上打印出的时黑白的。

      

    public class Test {
        public static void main(String[] args) {
          show(new Cat());  // 以 Cat 对象调用 show 方法
          show(new Dog());  // 以 Dog 对象调用 show 方法
                    
          Animal a = new Cat();  // 向上转型  
          a.eat();               // 调用的是 Cat 的 eat
          Cat c = (Cat)a;        // 向下转型  
          c.work();        // 调用的是 Cat 的 work
      }  
                
        public static void show(Animal a)  {
          a.eat();  
            // 类型判断
            if (a instanceof Cat)  {  // 猫做的事情 
                Cat c = (Cat)a;  
                c.work();  
            } else if (a instanceof Dog) { // 狗做的事情 
                Dog c = (Dog)a;  
                c.work();  
            }  
        }  
    }
     
    abstract class Animal {  
        abstract void eat();  
    }  
      
    class Cat extends Animal {  
        public void eat() {  
            System.out.println("吃鱼");  
        }  
        public void work() {  
            System.out.println("抓老鼠");  
        }  
    }  
      
    class Dog extends Animal {  
        public void eat() {  
            System.out.println("吃骨头");  
        }  
        public void work() {  
            System.out.println("看家");  
        }  
    }

      最终结果如下:

    吃鱼
    抓老鼠
    吃骨头
    看家
    吃鱼
    抓老鼠

      于是,我们可以看出多态存在的三个必要条件是继承、重写、父类引用指向子类对象。

      

      java抽象类。 即通过abstract class进行类的定义。说是抽象类,是因为我们约定这种类是抽象的,不能直接实例化得到对象,所以,这样的类就只能被继承。如果直接实例化抽象类就会编译错误。另外,抽象类中可以有抽象方法,抽象方法中不能有方法体。注意:抽象类不一定有抽象方法,但是有抽象方法的类一定是抽象类。

    • 构造方法、类方法(用static修饰的方法)不能声明为抽象方法。
    • 抽象类的子类必须给出抽象类中的抽象方法(如果有的话)的具体实现,除非该子类也是抽象类。

        java封装。我们知道面向对象的三大特征是继承、多态和封装,之前已经讲了继承和多态,这里就是将封装了

       封装(Encapsulation)是指一种将抽象性函式接口的实现细节部分包装、隐藏起来的方法。封装可以认为是一种保护屏障、防止该类的代码和数据被外部类定义的代码随机访问。要访问该类的代码和数据,必须通过严格的接口控制。

      封装最主要的功能就是我们能够修改自己的实现代码,而不用修改那些调用我们代码的程序片段。适当的封装可以让程式代码更容易理解和维护,也加强了程式码的安全性。

      封装的优点如下:

    1. 良好的封装能够减少耦合。
    2. 类内部的结构可以自由修改。
    3. 可以对成员变量进行更加精确的控制。
    4. 隐藏信息,实现细节。 

       
        实现java封装需要两个基本步骤,第一就是修改属性的可见性来限制对属性的访问(一般限制为private),第二就是对每个值属性提供对外的公共方法访问,也就是创建一对赋值、取值方法,用于对私有属性的访问。

         1、私有属性,对外隐藏。

    public class Person {
        private String name;
        private int age;
    }

        这些属性只有在类的内部可以访问,而其他的类是访问不了的,这样就实现了对细节的隐藏。

       

         2、提供公共方法,对外开放。

    public class Person{
        private String name;
        private int age;
    ​
        public int getAge(){
          return age;
        }
    ​
        public String getName(){
          return name;
        }
    ​
        public void setAge(int age){
          this.age = age;
        }
    ​
        public void setName(String name){
          this.name = name;
        }
    }

       如上所示,这些方法对私有属性进行访问,然后暴露出去。 其中,采用this关键字是为了解决实例变量和局部变量之间发生的同名的冲突 。

      

         java接口(Interface),在java编程语言中是一个抽象类型,是抽象方法的集合,接口通常以interface来声明。 一个类通过继承接口的方法,从而来继承接口的抽象方法。 

         java中的接口并不是类,接口包含的是类要实现的方法。 除非实现接口的类是抽象类,否则该类要定义接口中的所有方法

        接口无法被实例化,但是可以被实现。一个实现接口的类,必须实现接口内所描述的所有方法,否则就必须被声明为抽象类。

        接口的声明格式

    [可见度] interface 接口名称 [extends 其他的类名] {
            // 声明变量
            // 抽象方法
    }

        如下所示,就是一个接口:

    /* 文件名 : Animal.java */
    interface Animal {
       public void eat();
       public void travel();
    }  

      ok,在声明了接口之后,如何实现接口呢? 即类使用implements关键字实现接口,如下所示:

    /* 文件名 : MammalInt.java */
    public class MammalInt implements Animal{
     
       public void eat(){
          System.out.println("Mammal eats");
       }
     
       public void travel(){
          System.out.println("Mammal travels");
       } 
     
       public int noOfLegs(){
          return 0;
       }
     
       public static void main(String args[]){
          MammalInt m = new MammalInt();
          m.eat();
          m.travel();
       }
    }

      

      接口的继承。一个接口能继承另一个接口,使用extends关键字即可,即子接口继承父接口。如下就是Sports接口被Hockey和Football接口继承。  

    // 文件名: Sports.java
    public interface Sports
    {
       public void setHomeTeam(String name);
       public void setVisitingTeam(String name);
    }
     
    // 文件名: Football.java
    public interface Football extends Sports
    {
       public void homeTeamScored(int points);
       public void visitingTeamScored(int points);
       public void endOfQuarter(int quarter);
    }
     
    // 文件名: Hockey.java
    public interface Hockey extends Sports
    {
       public void homeGoalScored();
       public void visitingGoalScored();
       public void endOfPeriod(int period);
       public void overtimePeriod(int ot);
    }

      即Hockey接口自己声明了四个方法,从Sports接口继承了两个方法,那么实现Hockey接口的类需要实现六个方法。相似的,实现Football接口的类需要实现五个方法,其中两个来自Sprots接口。

      

      在java中,类的多继承是不允许的,但是接口允许多继承,使用extends关键字即可:

    public interface Hockey extends Sports, Event

      接口这里需要理解的: https://www.zhihu.com/question/20111251

      即接口并不是可有可无的,通过接口,我们知道哪些方法必须被实现,可以有一个预知的作用。

    比如说你今年放假出去杭州旅游,玩了一上午,你也有点饿了,突然看到前面有个店子,上面挂着KFC,然后你就知道今天中饭有着落了。

    KFC就是接口,我们看到了这个接口,就知道这个店会卖炸鸡腿(实现接口)。

    那么为神马我们要去定义一个接口涅,这个店可以直接卖炸鸡腿啊(直接写实现方法),是的,这个店可以直接卖炸鸡腿,但没有挂KFC的招牌,我们就不能直接简单粗暴的冲进去叫服务员给两个炸鸡腿了。

    要么,我们就要进去问,你这里卖不卖炸鸡腿啊,卖不卖汉堡啊,卖不卖圣代啊(这就是反射)。很显然,这样一家家的问实在是非常麻烦(反射性能很差)。
    要么,我们就要记住,中山路108号卖炸鸡,黄山路45号卖炸鸡(硬编码),很显然这样我们要记住的很多很多东西(代码量剧增),而且,如果有新的店卖炸鸡腿,我们也不可能知道(不利于扩展)。

      

      java包(package)

      为了更好的组织类,Java提供了包机制,用于区别类名的命名空间。所以,包的作用如下:

    • 把功能相似或者相关的类或者接口组织在同一个包中,方便类的查找和使用。
    • 就像文件夹一样,包也采用了树形目录的存储方式。同一个包中的类名字是不同的,不同的包中的类的名字是可以相同的,当同时调用两个不同包中相同的类名的类时,应该加上包名加以区别。因此,包可以避免命名冲突。
    • 包定义了访问权限,拥有包访问权限的类才能访问某个包中的类。

      所以,java中使用包(package)这种机制是为了防止命名冲突,访问控制,提供搜索和定位类(class)、接口、枚举(enumerations)和注释(annotation)等。

      比如一个Something.java文件的内容:

    package net.java.util;
    public class Something{
       ...
    }

      即,我们在定义一个类的时候,需要说明这个类的包,这样,它的路径应该是 net/java/util/Something.java 这样保存的。 package(包)的作用是把不同的java程序分类保存,更方便的被其他java程序调用。下面就是一些java的包:

    • java.lang - 打包基础的类 (即将java中一些基础的类打包到java.lang这个包中)
    • java.io - 包含输入输出功能的函数。

      开发者可以自己把一组类和接口等打包。并定义自己的包。并且这在实际开发中是值得提倡的,当你自己完成类的实现之后,将相关的类分组,可以让其他的编程者更容易地确定哪些类、接口、枚举和注释等是相关的。

      比如,我们可以在一个包中加入一个接口:

    /* 文件名: Animal.java */
    package animals;
     
    interface Animal {
       public void eat();
       public void travel();
    }

      然后在同一个包中创建一个类来实现这个接口:

    package animals;
     
    /* 文件名 : MammalInt.java */
    public class MammalInt implements Animal{
     
       public void eat(){
          System.out.println("Mammal eats");
       }
     
       public void travel(){
          System.out.println("Mammal travels");
       } 
     
       public int noOfLegs(){
          return 0;
       }
     
       public static void main(String args[]){
          MammalInt m = new MammalInt();
          m.eat();
          m.travel();
       }
    }

         这样,他们就会都保存在 animals 的子目录下。 

      

      而如果我们希望引入其他的类,可以 import payroll.* 来引入payroll这个包下面所有的类,或者通过import payroll.foo来引入payroll包下面的foo类。 

      通常,一个公司会使用它互联网域名的颠倒形式来作为它的包名。例如:互联网域名是run.com,那么所有的包名都会以 com.run 作为开头。 比如在com.run开头的com.run.test这个包,它包含了一个叫做Runoob.java的源文件,那么应该有如下目录:

    com/run/test/Runoob.java

      编译的时候,编译器会为包中定义的每个类、接口等类型各创建一个不同的输出文件,输出文件的名字就是这个类型的名字,并加上.class作为扩展后缀。

      编译之后的.class文件应该和.java源文件一样,他们放置的目录应该和包的名字对应起来,但是,并不要求路径完全一致,我们可以分开来安排源码和类的目录。

      

      

    十五、java数据结构、集合框架

      java工具包提供了强大的数据结构,在java中的数据结构主要包括以下几种接口和类,即枚举、位集合、向量、栈、字典、哈希表、属性。

    • 枚举是一种传统的接口,被迭代取代了,所以枚举已经很少使用 了。
    • 位集合(Bitset)实现了一组可以单独设置和清除的位或标志。
    • 向量(vector)和传统的数组非常相似,但是Vector的大小能根据需要动态的变化。即Vector类最主要的好处就是在创建对象的时候不必给对象指定大小,它的大小会根据需要动态的变化。即vector是一个动态数组。
    • 栈(Stack)实现了一个后进先出(LIFO)的数据结构。当你在栈中添加一个新元素时,就将新元素放在了其他元素的顶部。即最后进栈的元素最先被取出。其实栈是Vector的一个子类,它除了Vector定义的所有方法,自己也定义了一些方法,比如empty()判断栈是否为空、peek()查看栈顶部的对象、pop()可以移除栈顶部的对象、push()可以把对象压入栈的顶部、search(Object element)可以返回对象在栈中的位置。
    • 字典(Dictionary) 是一个抽象类(即只能被继承,不能实例化),它定义了键映射到值的数据结构。当你想要通过特定的键而不是整索引来访问数据时,这时候就要使用Dictionary了。
    • 哈希表(Hashtable) 是提供了一种在用户定义键结构的基础上来组织数据的手段。
    • 属性(properties) 表示一个持久的属性集。

      java结合框架即java collection framework,简称JCF,和c++中的STL(standard Template Library)是类似的。JCF设计参考了STL,但是其定位并不是java版的STL,而是用于实现一个精简紧凑的容器框架。

      java容器就是可以容纳其他java对象的对象,JCF是为java开发者挺了通用的容器,其始于JDK1.2,优点是可以降低编程难度、提高程序性能、提高API间的互操作性、降低学习难度。  

      Java容器里只能放对象,对于基本类型(int, long, float, double等),需要将其包装成对象类型后(Integer, Long, Float, Double)才能放到容器里。很多时候拆包装和解包装能够自动完成,这虽然会导致额外的性能和空间开销,但是简化了设计和编程。

      

      泛型。 java容器能够容纳任何类型的对象,这一点表面上是通过泛型机制完成的。java泛型不是什么神奇的东西,只是编译器为我们提供的一个“语法糖”。 

    十六、java泛型

      泛型是java中一个非常重要的概念,这个概念在Typescript中也是存在的,所以学好java中的泛型还是非常有必要的。 

      java泛型是JDK5中引入的一个新特性。泛型提供了编译时类型安全监测机制,该机制允许程序员在编译时检测到非法的类型。

    比如我们又这样的一个需求:写一个排序方法,能够对整型数组、字符串数组甚至是其他任何类型的数组进行排序,该如何实现?

      答案即使使用java泛型。 

      比如我们可以使用泛型来定义类/接口:

    public class Test<T> {
    
       private T obj;
    
       public T getObj() {
         return obj;
       }
    
        public void setObj(T obj) {
           this.obj = obj;
       }
    }

      

      泛型中的通配符。

    1. 无边界通配符(<?>) - 主要作用是可以让泛型接受未知类型的数据。
    2. 固定上边界通配符(<? extends E>)- 能够接受指定类及其子类类型的数据。 其中E指的是该泛型的上边界。
    3. 固定下边界通配符(<? super E>)- 能够接受指定类及其父类类型的数据。

      

      

      

      

      

      

      

      

      

      

     

      

      

  • 相关阅读:
    java入门 (七) 面向对象(三)
    java入门 (七) 面向对象(二)
    java入门 (七) 面向对象(一)
    ajax异步请求,$.each遍历拼接数据
    java入门 (六) 数组(二)
    java入门 (六) 数组(一)
    java入门 (五) 方法
    微信小程序
    776C Molly's Chemicals --- 前缀和
    CF 458C Elections --- 三分|线段树
  • 原文地址:https://www.cnblogs.com/zhuzhenwei918/p/8847296.html
Copyright © 2020-2023  润新知