Java

第一个Java程序

程序的操作流程

  • 1.先写出可执行的代码
  • 2.在命令框之中使用javac “文件地址”运行后,生成一个class字节码文件
  • 再在命令框中使用java “文件名称”运行代码
    即为将class文件装载进入JVM(类加载器)当中,再去硬盘上查找该文件进行运行。
  • 得到执行结果

helloworld

程序概况

  • 程序如下
    public class HelloWorld{
    public static void main(Strings[] args){
    System.out.println(“Hello World!”);
    }
    }

  • 注意:该程序在命名时,文件名称必须和public class后面的名称一致。

  • 对于HelloWorld程序的解释

    • 1.public 是表示公开的(关键字)

    • 2.class 用力声明一个类(关键字)

    • 3.HelloWorld 是一个类名

    • 4.每一句Java语句都必须用;结尾,代码自上而下执行。

    • main 即为程序的入口,又叫做主方法,main后{}中的称为方法体。

    如何给Java程序添加注释

    注释的三种方式

    • 第一种:单行注释

      • //单行注释,两个正斜杠后面的内容为注释内容。
    • 第二种:多行注释

      • /*

      • *这里的注释信息为多行注释

      • *第一行注释内容

      • *第二行

      • */

    • 第三种:javadoc注释

      • /**

      • *@author 作者名字

      • *@version 版本号

      • *@since 自从哪个版本开始就存在了

      • */

      • 对于Javadoc注释来说,这里的注释内容会被javadoc.exe解析并生成帮助文档。

    注释应该怎么写

    • 通常在类和接口处写,这一部分的注释是必须的。在这里我们可以使用javadoc.exe注释,表明创建者,时间,版本,以及类的应用。
    • 对于入参,出参,返回值,均要标明。
    • 对于常量,标明该常量的用途。

    public class和class的区别

    • 在同一个Java文件之中,public class定义的公共类名只能有一个,而且这个文件若是A.java 则被public class定义的类名只能是A。

    • 在源文件之中,我们可以使用class创建多个类来使用,但是类的名称不能重复,在每一个类中我们都可以编写main方法,想让程序从哪个入口执行,则加载哪个类即可。

Java基础语法

标识符

标识符的命名规则

  • 标识符只能以数字,字母,下划线,美元符号组成。

  • 标识符不能以数字开头。

  • Java关键字和保留字不能作为标识符。

  • 严格区分大小。

  • 没有长度限制。

关键字

关键字即是Java系统中自己定义的常量,有些表示数据类型,或是数据结构。

字面值

字面值其实就是数据

Java中的字面值

  • 1.整数型字面值

  • 2.浮点数型字面值

  • 3.布尔字面值

  • 4.字符串型字面值

  • 5.字符字面值(单引号括起来的单个字符)

数据类型

  • 例如:
    float i=1.0;
    int n=(int)i;

    注意:

    • 在数据的强制转化之中,可能会造成精度丢失,要慎重。(大容量转向小容量,即为上面的例子。)

    • 也有一种转化为自动转化,即为小容量向大容量转化。

    • 不同的类型在进行运算时,先转化成为容量最大的那个类型,再进行运算。

    难点

    • 对于下面的程序

      byte a=3;
      byte b=a+4;
      byte c=3+4;

      • 这个程序的第二句会报错,然而第三句却不会,这是为什么呢?

        • 因为第二句中是byte类型加上int类型,他们会先转化为int再进行运算,编译器认为byte+int可能会超出byte的值,而且a还是一个变量,所以报错了。但是第三句中,3和7都是常量不是变量,可以直接计算出来是7,而这个7也没有超出byte的范围,所以编译又通过了。

    数据类型转为字符串如何转

    • 只需要在数据后面加上加号输出即可。
      public class StringTurn {
      public static void main(String[] args) {
      int i =1;
      double e= 2.11;
      float x=3.11f;
      String i1=i+"";
      String e2=e+"";
      System.out.println(i1);
      System.out.println(e2); }
      }

      那么字符串类型转为其他数据类型该怎么办呢?

    语法:需要用到基本类型的包装类调用parseXX方法即可
    • 要转换谁,就使用基本类型的包装类调用parseXX方法

      • eg:转换为整数使用Integer.parseInt()

        • Float.parseFloat()
    • Double.parseDouble()

      • Bollean.parseBoolean()

      • 那么字符串如何转化为字符类型呢,我们需要的是把字符一个一个取出来,就像python的集合一样

        • eg:System.out.println(s.charAt(0));此刻我们假设s为一个字符串,我们取出他的第一位。

运算符

算数运算符

  • +(加),-(减),*(乘),/(除),%(取余符号)

    单目运算符

    • ++,对数字自加1

    • –,对数字自减1

    • Java中规定,当单目运算符出现在变量之后时,会先做赋值运算。即=的优先级在此时高于++。

      • 比如b=a++,此时会先将值赋给b再进行加一运算,那么b=++a,此时a会先进行加一运算再赋予b。
    • 下面我给出一道经典的面试题

      int i=1;
      i=i++;
      System.out.println(i);
      i最后等于什么?为什么?

      • 这其中有一个临时变量,我来写出每一步
        1.temp =i 2.i=i+1 3. i=temp
    • 其中temp就是电脑执行这行命令时,所创造出的临时变量。

关系运算符

  • >,>=,<,<=,==,!=

  • 此关系符输出的是bool值

逻辑运算符

  • &逻辑与

    • ture&true——true

    • flase&ture———flase

  • |逻辑或

    • ture|flase——true
  • !逻辑非

    • !true——flase

    • !flase——true

  • &&短路与

  • ||短路或

  • 短路,即为惰性原则,当&&判断出第一个是flase时,不会去计算后面的式子,而是直接输出flase,这就叫发生了短路。

  • 运算结果为bool值

赋值运算符

  • =

  • +=

  • -=

  • *=

  • %=

  • /=

  • 这几种全是赋值运算符,除去第一个,其他的全都是式子的简写,我以第二个为例子

    • a+=1就是a=a+1,其余的也一样,可以在编程中简化代码

字符串连接运算符

  • 字符串连接符即为➕,当➕两边有一边是字符串类型时,会进行字符串的拼接。

  • 字符串拼接时,会从左向右依次执行eg:

    a+“+”+b+“=”+a+b

    • 第一个加号是字符串,第二个是字符串连接符,执行下来的结果为a+b=a+b
  • 当左右连接的是字符串时,会将其连接,但是如果是字符时,会将其转换成为阿斯克码再进行相加的运算。

条件运算符(三目运算符)

  • 语法结构: 布尔表达式:表达式1?表达式2;

  • 若布尔表达式为true,执行表达式1,若为flase,执行表达式2。

位运算符

  • &按位与,|按位或,^按位异或,~按位取反,<<左移,>>右移(带符号),>>>不带符号右移。

其他运算符

  • instanceof

  • new

控制语句

选择语句

if
  • if语句一般的编写方式如下

    if(布尔表达式){
    java语句;

}
else if(布尔表达式){
java语句;

}
else{java语句;
}- 如果布尔表达式值为true就执行当前if语句中大括号内的代码。
switch
  • switch的编写方法一般如下

    switch(int/string){
    case int/string:
    java语句;
    break;
    case int/string:
    java语句;
    break;

    case int/string:
    java语句;
    break;
    default:
    java语句;

    }

    • 当switch括号内的值等于case括号内的值时,就执行当前case语句下面的java语句,如果没有匹配的值,就执行default下面的java语句
  • 注意:每一个case的java语句写完后,都要加上break语句来终结本次选择语句的执行。

循环语句

for
  • for语句的语法结构如下

    for(初始化表达式;布尔表达式;更新表达式){
    java语句;
    java语句;
    java语句;
    java语句;
    }

    • for循环中,先执行初始化表达式,再判断布尔表达式,如果布尔表达式为true,则开始执行循环体,当执行完循环体时,再执行更新表达式,最后再对布尔表达式进行判定,如果为ture则继续执行循环体,如果为flase就结束循环。
while
  • while循环结构如下

    while(布尔表达式){
    循环体;
    }

    • 当布尔表达式为true时,循环会一直执行下去,直到布尔表达式为flase。
do……while
  • do……while循环结构如下

    do{
    循环体;
    }while(布尔表达式);

    • 它会先执行循环体,再进行条件判断,如果为true,则继续循环,如果为flase就终止循环。
转向语句
  • break

    • 被用于循环体中,用来跳出循环。
  • continue

    • 被用于终止本次循环,继续进行下一次循环。
返回语句
  • return

    • 当函数有调用时,用于返回值到函数调用处。

方法(内含Java虚拟机的内存管理)

方法的作用

  • 方法的出现,极大的提高了编程的效率,当一个功能需要重复实现时,就可以用上方法来简化程序。

方法的声明和调用

  • 方法的定义语法如下

    ​ [修饰符列表]返回值类型 方法名(形参列表){
    ​ 方法体;
    }

    • 修饰符列表,这个是可选的不是必须的。

    • 返回值类型,可以是Java的任何一种数据类型,当一个方法执行完成后,没有返回值时,必须写成void。

    • 方法名,这项必须是合法的标识符,可以看出来方法的作用。

    • 形式参数列表,当有多个形参时,通常使用“,”进行分离。

    • 方法体,由Java语句构成,代码遵循自上而下的顺序依次执行。

  • 当写完一个方法的定义后,这个函数就已经声明了。

  • 方法的调用实在主函数中,写出“类名.方法名.(实际参数列表);”

  • 有些情况下,类名可以被省略。

    • 当在方法a中执行方法b时,而且方法a与方法b的类相同时,b的类名可以被省略。

方法的形参和实参

  • 方法在调用时,其实参必须和形参一一对应

  • 形参和实参类型也必须一一对应,当然有些时候会出现类型的自动转化,比如int转long

方法的返回值

  • 返回值会使用return语句,返回我们需要的值回到方法调用处。

  • 方法的返回值必须和定义函数时写下的类型相同,不然会报错。

方法的重载和调用时其内存变化

  • 要知道内存变化,我们先要了解一个数据结构:栈(stack)

  • 如上图所示,向一个栈插入新元素,叫做进栈,入栈或是压栈(push),它将新元素放在栈顶元素的上面,使他成为新的栈顶元素;同样的将栈的元素删除称为出栈,退栈又称弹栈(pop),它是将栈顶元素删除来实现。

  • 栈的限制是:仅允许在表的一边进行添加和删除的操作。

  • 知道了栈的数据结构后,我们来看一张图


- 当Java程序开始实现时,先通过类加载器系统找到字节码文件,再将其加载到虚拟机中的方法区当中,开始调用main方法,main方法在被激活的瞬间,会在栈中给他分配活动空间,此时是压栈动作,main在栈底。- 当Java程序执行完成后,会释放内存发生弹栈动作,main方法最后一个被放出,所以我们说当main方法结束时,这个程序也就结束了是不无道理的。#### 对于图上各个点的解释##### 线程的概念- 线程是操作系统中能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。
程序计数器
- 概念:可以看做当前线程所执行的字节码的行号指示器。- 特点:线程私有的内存。
Java虚拟机机栈
- 概念:描述的是Java方法执行的内存模型
- 特点:线程私有,生命周期和线程相同。这个区域会出现两种异常。分别是StackOverflowError异常:线程请求深度大于虚拟机所允许的深度。  OutOfMenmoryError异常:若虚拟机可以动态扩展,如果扩展是无法申请到足够的内存。
本地方法栈
- 概念:他与虚拟机栈所发挥的作用是相似的,区别是Java虚拟机栈为Java方法服务,而本地方法栈为本地方法服务。- 特点:他也有和Java虚拟机机栈相同的异常。
Java堆
  • 概念:是被所有线程共享的一块区域,在虚拟机创建时创建。

  • 特点:线程共享,存放的是对象实例,GC管理的主要区域可以处于物理上不连续的区域。

方法区
  • 概念:存储已经被虚拟机加载的类信息,常量,静态变量,即时编译器编译后的代码等数据。

  • 特点:线程共享区域,抛出异常OutOfMemory异常:当方法去无法满足内存分配需求时。

方法重载

方法重载的定义:
是在一个类中定义多个同名的方法,但要求每个方法具有不用的参数类型或者是参数个数
作用:
在调用重载方法时,java编译器可以通过检查调用方法的参数类型和参数的个数来选择一个合适的方法。
满足的条件
  • 1.在同一个类中
  • 2.方法名相同
  • 3.参数列表不同
    • 个数不同算不同
    • 顺序不同算不同
    • 类型不同算不同

递归

递归的定义

递归就是在m()之中又调用了m()方法,方法调用方法自身,就构成了递归。

注意事项

  • 1,递归函数得在自己的函数中调用自己,才能一步步自己执行下去。

  • 2,递归函数得自己设定结束的标志,不然会一直运算下去

生活实例

可以解决各种生活问题,比如汉诺塔,阶乘问题,迷宫问题,球和篮子的问题,算法中也会用到递归,比如快排,归并排序,二分查找等

例子:计算1~n的和
public class Test{public static void main(Strings[]args){int n=99;int result=accumulate(n);System.out.println("1~n的和是"+result);}public static int accumulate(int n){int result=0;if(n==1){return 1;}return n+accumulate(n-1);}
例二:汉诺塔

规则:1、有三根相邻的柱子,标号为A,B,C。

​ 2、A柱子上从下到上按金字塔状叠放着n个不同大小的圆盘。

​ 3、现在把所有盘子一个一个移动到柱子B上,并且每次移动同一根柱子上都不能出现大盘子在小盘子上方。

代码实现:

public class hannuota {public static void main(String[] args) {class Tower{public void lujing(int num,char a,char b,char c){if(num==1){System.out.println(a+"->"+c);}else{lujing(num-1,a,c,b);System.out.println(a+"->"+c);lujing(num-1,b,a,c);}}}Tower t=new Tower();t.lujing(n,'A','B','C');}
}
例三:小老鼠走迷宫

小老鼠需要从左上角走到右下角,该怎么实现?

public class mouse {public static void main(String[] args) {int [][]migong=new int[8][7];for(int i=0;i<7;i++){migong[0][i]=1;migong[7][i]=1;}for(int i=0;i<8;i++){migong[i][0]=1;migong[i][6]=1;}migong[3][1]=1;migong[3][2]=1;
for(int i=0;i<migong.length;i++){for(int j=0;j<migong[i].length;j++){System.out.print(migong[i][j]);System.out.print(" ");}System.out.println(" ");
}System.out.println("==============");
class a{public boolean foundway(int [][]a,int i,int j){if(a[6][5]==2){return true;}else if(a[i][j]==0){a[i][j]=2;if(foundway(a,i+1,j)){return true;}else if(foundway(a,i,j+1)){return true;}else if (foundway(a,i-1,j)){return true;}else if(foundway(a,i,j-1)){return true;}else{a[i][j]=3;return false;}}else {return false;}}
}
a A=new a();A.foundway(migong, 1, 1);for(int i=0;i<migong.length;i++){for(int j=0;j<migong[i].length;j++){System.out.print(migong[i][j]);System.out.print(" ");}System.out.println(" ");}}
}

红色的就是小老鼠走过的路程。

this和static的用法

this

this可以看作一个引用,储存在java虚拟机内部,this这个引用保存了当前对象的内存地址指向自身,每一个堆内存的java对象都有一个this。

this引用和变量名引用其实是可以画等号的,都是指向对象的属性。

this不能出现在static的方法里面,因为static方法里面调用时不需要创建对象,直接采用类名调用,所以不用使用当前对象调用,因为this是和当前对象划等号的。

换句话来说this是出现在实例方法里面的。这个实例方法里面正在调用的对象是谁,this就是谁。

this在构造方法中

使用在构造方法的第一行,调用他时的语法格式是this(实际参数列表)。

很大程度上来说this简化了程序,当实参进入程序时,实参名等于this名,可以直接使用,提高了代码的可维护性。

static

表示”静态的“,它可以被使用来修饰变量,方法,代码等,修饰方法时叫做静态方法,变量叫静态变量,代码叫做静态代码块。

凡是使用static修饰的都是与类相关的,直接通过类名访问。

static使用时,即代表这个数值不会根据对象的改变而改变,如果根据对象的改变而改变了,那么就应该时实例对象,而不是静态对象。

静态代码块
  • 就是在代码块外围大括号前面写上static。

    • 他会在类加载时运行,并且只执行一次。

    • 在静态代码块中出现实例变量会报错,我们只需要在给实例变量定义时前加上static即可,这表示该变量是一个静态变量。

      静态方法
  • 一般是工具类的方法,会有利于开发,方便调用,直接使用类名就可以使用。

输入语句

用到了扫描器scanner=>他是简单文本扫描器

步骤

  • 第一步:导入包,java.util.Scanner

  • 第二步:创建一个对象,就是new()在面向对象中写过如何创建一个对象。

  • 第三步:接受键盘输入

数组(引用类型)

定义一个数组

  • 比如:double [ ]hens ={1,5,9,7,9,5};

    • double代表这个数组的类型,hens代表这个数组的名称。

遍历数组(利用for循环)

  • eg:利用for循环从hens[i]来循环,i=0然后慢慢递增,直到第5个,就将这个数组遍历完了。

  • 这是代码

  • 这是执行后的成果

数组的使用及其初始化

初始化方法
  • 1.静态初始化
  • 2.动态初始化
  • 3.直接赋值
  • 使用细节

  • 1.数组是多个同类型数据的组合,实现对这些数据的统一管理。

  • 2.不能高精度值赋给低精度类型,比如不能把double类型的数据放入int数组。

  • 3.数组的数据类型,不能混用。

  • 4.在数组创建后,没有的赋值时,默认值为0。

  • 5.数组是引用类型,数组型数据是对象(object)。

数组的赋值规则

  • 拷贝赋值
    • 就是基础类型之间的直接赋值,比如下面的代码,当我们改变n2的值时,n1不会受到影响。这与jvm的内存系统有关。

      int n1=10;
      int n2=n1;
      in2=20;

    • 在给n1赋值时将10直接给了n1,在执行n2=n1时,会将n1的值10直接拷贝到n2的值上,这就叫做拷贝复制,当我们改变n2的值时,n1便不会受到影响。

  • 引用赋值
    • 数组在默认情况下是引用传递,赋的值是地址,赋值的方式为引用赋值。

    • 下面我用一段代码来说明

      int []arr1={1,2,3};
      int []arr2=arr1;
      arr2[0]=10;

      • 当我改变了arr2[0]的值时,arr1这个数组的值也会改变,这是因为在jvm里面存放时,数组指向的不是具体的值,而是一个空间,这个空间的名字叫地址,这个空间里面来存放数据,当我们将arr1数组赋给arr2数组时,是将他的地址赋给了arr2,那么此时arr2这个数组,也可以直接访问这个地址,当我们改变arr2的值时,相当于改变了这个地址上面的值,arr1也会随之改变。
  • 数组拷贝(得到新数组,不和上一个有关联)

  • 1.先new一个新数组,int arr1=new int [arr1.lenght];

  • 2.然后使用for循环遍历救数组,将旧数组的值赋给新数组。

  • 数组扩容

  • 给int arr[]={1,2,3};后面扩容,加上4,使其变成{1,2,3,4}

    • 方法
    • 1.定义初始数组

    • 2.定义一个新的数组

    • 3.遍历初始数组,依次将初始数组的元素拷贝到新数组上

    • 4.让初始数组指向新数组,那么原来的数组将会被销毁

    • 代码实现
    • 原理
      • 主要是最后一步的指向,是将新数组的地址赋给旧数组的地址,从而使得旧数组的地址被销毁。
  • 那我们现在写一个程序让用户自己决定什么时候停止给数组扩容

    import java.util.Scanner;
    public class shuzu {public static void main(String[] args) {int a[] = {1,2,3};do {Scanner s=new Scanner(System.in);System.out.println("input number");int w=s.nextInt();int newa[]=new int[a.length+1];for(int i=0;i<a.length;i++){newa[i]=a[i];}newa[a.length]=w;a=newa;for(int x=0;x<newa.length;x++){System.out.println(a[x]);}System.out.println(" if you want continue please input 1");int x=s.nextInt();if(x==1){break;}}while(true);}
    }
    
  • 数组中查找东西

    • 1.定义一个字符串数组。

    • 2.接受用户输入,遍历数组,进行逐一比较,如果有,则提示信息,并推出。

    • 代码实现

      import java.util.Scanner;
      public class found {public static void main(String[] args) {String a[]={"mike","anna","davi"};Scanner d=new Scanner(System.in);System.out.println("please input name");String name=d.next();for(int i=0;i<a.length;i++){if(a[i].equals(name)){System.out.println("yes,you found it");}else if(i==a.length-1){System.out.println("sorry");}}}
      }
      

多维数组

  • 多维数组

    • 二维数组
      • 什么是二维数组
        • 从定义和形式上看,就是原来的每个元素都是一个数组,这样就是二维数组。
      • 两种创建方法
        • 第一种直接赋值创建
        • 就是直接赋值的方法
      • 第二钟动态创建
        int arr[][]=new int[2][3];
        arr[1][1]=3;

        • 列数不确定创建,即为一维数组中的元素不相同。

          • int[][]arr=new int [3][];

          • 就是给上面的一维数组开空间,然后可以分别给一维数组的每个元素赋值。

      • 遍历方法
        • 套用两层循环来实现

        • 代码实现

          public class DoublEshuzu {
          public static void main(String[] args) {int a[][]={{1,0,1,3},{5,4,1,4},{5,4,8,7}};for(int i=0;i<a.length;i++){for (int j=0;j<a[i].length;j++){System.out.print(a[i][j]+"\t");}}}
          }
          
        
        
      输出10行杨辉三角
      public class YangHui {public static void main(String[] args) {int [][]a=new int[10][];for(int i=0;i<a.length;i++){a[i]=new int[i+1];for(int j=0;j<a[i].length;j++){if (j == 0 || j == a[i].length-1){a[i][j]=1;}else{a[i][j]=a[i-1][j]+a[i-1][j-1];}}}for(int i=0;i<a.length;i++){for (int j=0;j<a[i].length;j++){System.out.print(a[i][j]+"\t");}System.out.println(" ");}}}
      
  • 作业
随机生成10个整数(1~100)保存到数组,并倒序输出求出其打印值,求最大值和最小值的下标,并查找里面是否有8
代码实现
public class homework {public static void main(String[] args) {int []b;int sum =0;double HalfSum=0;b=new int[10];for(int i=0;i<10;i++){int a=(int)(Math.random()*100+1);b[i]=a;}int max=b[0];int min=b[0];for(int j=9;j>=0;j--){System.out.print(b[j]+" ");if(b[j]==8){System.out.print("yes");}sum += b[j];HalfSum=sum / 10;}System.out.println(" ");System.out.println(sum);System.out.println(HalfSum);for(int k=0;k<10;k++){if(max<b[k]){max= b[k];}if(min>b[k]){min=b[k];}}for(int f=0;f<10;f++){if (b[f]==max){System.out.println("max is"+f);}if(b[f]==min){System.out.println("min is"+f);}}}}

类与对象

为什么引入类与对象这个方法,我们从一个问题中来得到答案
王奶奶有两只小猫,一只5岁黑色公猫,一只6岁黄色母猫,现在编写程序来输入一只猫,得到这只猫的所有信息,如果输入的猫不是王奶奶的猫,则说明错误。

这个问题中,我们首先想到使用变量来实现,我们会发现,变量太多代码程序繁杂,那么我们再考虑使用数组来实现,数组在使用的过程中,我们不能统一数据类型进行使用,也是行不通的。

这时候,我们使用类与对象的方法来解决这个问题。

类和对象的关系

  • 把猫所有的特性提取出来构成一个猫类,这些特性的数据类型各不相同,把每个猫的特性数据集合到一起,构成一个对象。这个对象就是一个具体的实例。

代码实现

  public class oop {public static void main(String[] args) {class cat{int age;//这里进行了猫类的创建,并且在猫类里面说明了猫的特性。}cat cat1=new cat();//创建了猫对象cat1.age=10;//给cat1对象的属性赋值System.out.println(cat1.age);}
}

如果要增加猫的属性,比如名字,直接再class cat里面加入名字这个特性即可。

对象在内存中的存在形式

基本数据类型会直接存储到堆里使用,非基本数据类型比如说字符串,会在堆里面存储地址,这个地址指向方法区里面的空间,在方法区这个空间存储变量。

属性和成员变量

基本概念:从概念和叫法上看,成员变量等于属性等于field(字段)

属性是类的一个组成部分,一般是基本数据类型,也可以是引用类型,比如说我们在猫类里面定义的age就是一个属性。

注意事项和细节说明

  1. 属性定义语法和变量相同,需要输入相同类型的值。
  2. 属性的定义类型可以为任何类型,包含基本类型和引用类型。
  3. 属性不赋值的情况下,有默认值,规则和数组相同。

对象其实是他里面的东西,cat1只是他的对象名,真正的对象是new出来的对象空间,即为new cat() 。

成员方法

基本概念:在某些情况下,我们需要定义成员方法,比如人类除了年龄性别这些属性外,还有一些行为,这些就需要通过成员方法来完善。

public class oop {public static void main(String[] args) {class cat{int age;public void eat(){System.out.println("i like eat");}}cat cat1=new cat();cat1.age=10;cat1.eat();//调用eat方法System.out.println(cat1.age);}
}

这里的eat方法就是我定义的成员方法。

成员方法在jvm内存的储存空间

成员方法的定义方法
public 返回类型 方法名(形参列表){方法体内的语句;return 返回值;
}

public是访问修饰符,有四种类型,用于控制方法生效的范围
四种分别是:public, 不写, potected, private。

细节问题
方法不能嵌套定义,即不能在方法里面定义方法
如何跨类调用方法
class A{public void m(){System.out.println("调用了a类中的m方法");}public void n(){System.out.println("调用了a类中的n方法");}
}
class B{public viod am(){A a =new A();a.m();a.n();}
}
B b=new B();
b.am();
成员方法的传参机制
基本类型的传参机制

在方法中修改方法外部的数值,只要不return回去重新赋值,这个方法在执行完后会直接释放内存,不会影响外部的数值。不会修改地址。

引用类型的传参机制

比如数组来说,传递进去的是数组,即为地址,不是值。假如现在有一个方法用于交换数组当中的值,方法在调用时会,开辟一个新的栈来使用,这个方法在使用时,会对堆里面的地址进行改变,当方法执行完成后,这个方法栈被释放内存,但是这个堆里面的地址会永久的改变,这与基本类型不同,传递参数会影响到外部的值。会修改地址。 还有一种是传入对象,对象的本质也是地址,综上所述,这个只要传入的是地址,就会改变值。

如何将对象作为参数传入方法中呢?
比如现在的类是Person,在方法()里面输入Person b即可,这示意在Person建立一个对象b传入方法之中。

了解了这么多,我们可以实现对象的克隆,属性情况都相同,但是输出的是两个不同的对象,下面是代码实现。

public class oop {public static void main(String[] args) {class Person {int age;String name;double high;}class copy {public Person copyPerson(Person b) {Person a=new Person();a.high=b.high;a.name=b.name;a.age=b.age;System.out.println(a.age);return a;}}Person b=new Person();b.age=11;b.name="mike";b.high=187.2;copy x=new copy();Person a=new Person();a=x.copyPerson(b);}
}

注意的点

一个是return出来的值需要去接收,所以我重新建立了一个新的对象a来接收方法执行中被克隆出来的对象。

第二个是方法如果要返回这个对象,他的返回值类型不能为void而是要返回的类名称,即为Person。

第三个是要使用方法时,需要先建立这个类的对象,再对象.方法名(),进行shi’y

重载(OverLoad)

基本介绍

介绍

Java中允许在一个类中,多个同名方法存在,但是要求形参列表不一致。比如说输出打印的方法,System.out.print()这个函数,什么都可以输出,比如说字符串,字符,布尔值,数字啥的。在这里的out其实就是一个对象,形参都不同,这种就叫方法的重载。

好处

1,减轻了起名的麻烦。

2,减轻了记名的麻烦。

例如
public class overload {public static void main(String[] args) {class num{public int num(int a, int b){return a+b;}public double num(double a,int b){return a+b;}public double num(int a,double b){return a+b;}public  double num(double a,double b){return a+b;}}num n=new num();System.out.println(n.num(5.3,6));System.out.println(n.num(5,4));System.out.println(n.num(6.6,4.2));}
}

运行正常,例子我用的是两位数的和方法,可以输出整数或者浮点数。

细节

方法名:必须相同。

参数列表:必须不同。(形参类型,形参个数不同都可以构成方法重载)

返回类型:无要求。

练习题

在m类中定义max()方法,输入两个int值时输出较大值,输入两个double值时输出最大值,输入三个double值时输出最大值。
public class overload {public static void main(String[] args) {class m {public int max(int a, int b) {if (a > b) {return a;} elsereturn b;}public double max(double a, double b) {if (a > b) {return a;} else return b;}public double max(double a, double b, double c) {if(a>b&&a>c)return a;else if (b>a&&b>c)return b;else if (c>a&&c>b)return c;return 0;}}m m=new m();System.out.println(m.max(5,6));}
}

可变形参

基本概念

Java中允许将同一个类中多个同名同功能但是参数个数不同的方法,封装成为一个方法。这里就可以通过可变参数来实现。

快速入门案例

比如在重载中,我们加多个int类型的值,相加两个,相加三个,就得写两个方法,但是我们使用可变参数,就可以把他整合成为一个方法。

public class VarParameter{public static void main(Srting[] args){HsMethod m= new HsMethod();m.sum();}
}
class HsMethod{public int sum(int... nums){int res =0;for(int i=0;i<nums.lenght;i++){res += nums[i];}return 0;}
}

我们现在观察上面的代码,其中的int… nums就代表可以接收int类型的值,数量是从0到n,这些数值会被保存到nums这个数组里面,当我们需要将其相加的时候,我们只需要遍历这个数组即可,极大的简化了程序。

注意事项

  1. 可变参数的实参为0个或者至多个。
  2. 可变参数的实质为数组。
  3. 可变参数可以和普通类型的参数一起放在形参列表,但需保证可变参数在最后放置。
  4. 一个形参列表只能出现一个可变参数。

练习

有三个方法,分别实现返回姓名和两门课程的总分,返回姓名和三门课的总分,返回姓名和五门课的总分,封装成一个可变参数的方法。

public class overload {public static void main(String[] args) {class b{public void student(String a,int... sums){int res=0;for(int i=0;i<sums.length;i++){res +=sums[i];}System.out.println(a);System.out.println(res);}}b a=new b();a.student("mike",4,5,7,8,9);}
}

作用域

基本使用

  1. 在java编程中,主要的变量就是属性(成员变量)和局部变量。
  2. 局部变量一般是指在成员方法中定义的变量。
  3. 全局变量:就是属性,作用域为整个整体。
  4. 局部变量:也就是除了属性以外的其他变量,作用域为定义它的代码块中。
  5. 全局变量可以不进行赋值,直接使用,因为它具有默认值,局部变量必须进行赋值后才可以进行使用,因为没有默认值。

注意事项和细节

  1. 属性和局部变量可以重名,访问时遵循就近原则。
    就近原则:比如有一个属性叫name=mike,在方法中的name=king,假如我们在创建对象后使用该方法输出name值,根据就近原则,会输出king这个值。那么我们接下来将方法中的name值给注销,再进行输出,就会输出mike这个值。
  2. 在同一个作用域中,两个变量名不能重名。
  3. 属性的生命周期长,伴随着对象的创建而创建,伴随着对象的死亡而死亡。局部变量,生命周期短,伴随着它的代码块执行而创建,伴随着代码块的结束而死亡,即在一次方法的调用中生效。
  4. 范围不同
    全局变量:可以被本类使用,也可以通过在其他类中通过对象调用来在其它类中使用。(一种是跨类调用,另外一种是将类当参数传入方法使用)
    局部变量:只能在本类中的对应方法使用。
  5. 修饰符不同
    局部变量不可以加修饰符。
    全局变量可以添加修饰符。eg:public ~ ~ ~

构造器constructor

什么时候使用?

当我们需要创建人类这个对象时,是先把一个对象创建好后,再给他的年龄和名字属性赋值,有了构造器,我们可以在创建人类对象时,直接指定这个对象的年龄和姓名。

作用:初始化新对象

基本语法

【修饰符】方法名(形参列表){

​ 方法体;

}

说明:

  1. 这里的修饰符可以不写,有默认值,也可以是public protected private
  2. 构造器没有返回值。
  3. 方法名必须和类的名字相同。
  4. 参数列表和成员方法一样的规则。
  5. 构造器的调用是由系统完成的。

快速入门

public class constructor {public static void main(String[] args) {class Person{String name;int age;public Person(String a,int b){name=a;age=b;}}Person p= new Person("mike",18);System.out.println(p.age);System.out.println(p.name);}
}

第十一行中在初始化对象时就定下了属性,输出结果正常。

注意事项和使用细节

  1. 一个类可以定义多个不同的构造器,即为构造器重载。(可以一个只给名字,一个给名字和年龄等等)

  2. 构造器名要和类名相同。

  3. 构造器没有返回值。

  4. 构造器是完成对象的初始化,不是创建对象。

  5. 在创建对象时,系统自动调用该类的构造方法。

  6. 如果程序员没有定义构造方法,系统会自动给类生成一个默认无参构造方法(也叫默认构造方法)比如Person(){},使用javap反指令反编译看看。

class Person {}

平常创建对象时,进行的 Person p=new Person();

这个小括号其实就是运行了默认的构造器。

反编译工具 javap

在cmd命令框里面运行

  1. 一旦定义了自己的构造器,默认的构造器就被覆盖了,就不能使用默认的无参构造器,除非显式的重新定义一下,例如:Person(){}

对象创建的基本流程

public static void main(String[] args){class b{int age;String name;public b(int a,String b){age=a;name=b;}}b B=new b(18,"mike");
}

在第10行中的代码,首先执行的是创建一个新对象,这个对象并不是B,这个对象是指向B的地址,即会在栈中创建一个地址用来存放值,当没有在b()中输入时,地址中的值为默认值,为null和0。在输入具体值后,会对默认值进行覆盖,至此,一个对象的创建便完成了。对象的实质是在栈中开辟的空间

this关键字

什么是this?

我们用一个案例来说明

public static void main(String[] args){class b{int age;String name;public b(int age,String name){age=age;name=name;}}
}

这里的形参为了方便我们看,我将它改为了属性名,但是这里存在一个问题,根据作用域的特点,这个方法中的name根据就近原则并不是属性名,而是形参,从这点来看,name=name和age=age就没有任何作用,这时候就引出了this关键字,这个关键字可以解决这个问题。代码实现如下

public static void main(String[] args){class b{int age;String name;public b(int age,String name){this.age=age;this.name=name;}}

这里的this就代指此处调用b()方法的对象,如果对象w调用b()方法,那么此时的this就代表w,实质上是w.name=name。

深入理解

对于内存存储的理解,在创建这个对象时,this作为隐藏属性存在其堆中,当使用this这个属性时,this会指向方法区中的一块地方,这个地方叫常量池,常量池中存在着对象的地址,使得this可以代替对象进行方法的调用,下面是图解

说白了,this会指向自己所在的对象空间,从而使方法得以使用。

使用细节

  1. 访问成员方法的语法
class{public void t1(){System.out.print("调用了f1方法");}public oid t2(){System.out.print(" 调用了f2方法");f1();this.f1();}
}

其中如果想要在f2中调用f1方法,可以为第七行,也可以为第八行。

  1. this还可以访问构造器,注意只能在构造器中使用(只能在构造器中访问另外一个构造器)。
    如果有this访问构造器这种语法,必须置于程序的第一行去执行

    A e=new A();
    class A{public A(){this("jake",100);System.out.print("使用了public A()构造器");}public A(String name,int age){System.out.print("使用了public A(String name,int age)构造器");}
    }
    

    程序中创建了a对象,使用了无参构造器,然后在无参构造器中访问了第二个构造器,进行访问。

    1. this不能在类定义的外部使用,只能在类中使用。

    练习

    定义Person类,里面有name,age属性,并提供compareTo比较方法,用于判断是否和另外一个人相等,提供测试类TestPerson用于测试,名字和年龄完全一样,就返回true,否则返回false。

    public class thiS {public static void main(String[] args) {class Person{String name;int age;public boolean compeTo(Person a,Person b){if(a.age==b.age&&a.name==b.name){return true;}else return false;}}}
    }

    这是不使用this关键字的程序,下面我使用this关键字来写一段。

    public class thiS {public static void main(String[] args) {class Person{String name;int age;public Person(String name,int age){this.name=name;this.age=age;}public boolean compareTo(Person p){return this.age==p.age&&this.name==p.name;}}Person p=new Person("mike",17);Person k=new Person("mike",17);System.out.println(p.compareTo(k));}
    }
    

Java中级编程

包的三大作用

  1. 区分相同名字的类
  2. 当类很多时,可以很好的管理类
  3. 控制访问范围

包的基本语法

package com.hspedu;

说明:

  1. package关键字,表示打包。
  2. com. hspedu 表示包的名称

包的命名

命名规则:只能包含数字,字母,下划线,小圆点,不能是关键字或保留字。

命名规范:一般是小写字母加小圆点eg:com.oa.model这种

常用的包

java.lang* 基本包,不需要引用,直接使用

java.utrl.* util包,系统提供的工具包,工具类,比如使用scanner

java.net.* 网络包,做网络开发

java.awt.* 做java的界面开发,GUI

导入包

import java.utrl.Scanner
import java.utrl.*

第一种是导入这个包里面的的scanner方法

第二种是直接导入这个包

在编程过程中,推荐使用第二种方法。

使用细节和注意事项

  1. package的作用是声明当前类所在的包,xvyaofangzaiclass的最上面,一个类中最多只能有一个package
  2. import指令位置放在package的下面,在类定义的前面,可以有多句,而且没有顺序要求。

访问修饰符

基本介绍

java提供四种访问控制修饰符号,用于控制方法和成员变量,属性的访问权限。

  1. 公开级别:使用public修饰,对外公开。
  2. 受保护级别:用protected修饰,对子类和同一个包中的类公开。
  3. 默认级别:没有修饰符,向同一个包的类公开。
  4. 私有级别:用private修饰,只有类本身可以访问,不对外界公开。

注意事项

  1. 修饰符可以用来修饰类中的属性,成员方法以及类。
  2. 只有默认的和public才能修饰类,并且遵守以上的访问权限的特点。

封装(encapsulation)

就是把抽象出来的数据和对数据的操作封装在一起,数据被保护在内部,程序的其他部分只有通过被授权的操作方法,才能对数据进行操作。

好处

  1. 隐藏实现的细节。
  2. 可以对数据进行验证,保证安全合理。

封装实现的步骤

  1. 属性私有化,让外部不能修改属性。
  2. 提供一个public方法,用于对属性判断并赋值。
  3. 提供一个公共的get方法,用于获取属性的值。

快速入门案例

设计一个小程序,不能随便查看别人年龄,工资等隐私。并对设置的年龄进行合理的验证,年龄合理就设置,否则给默认年龄,年龄介于1~~~~~100,姓名为2-6个字符

package test.encapsulation;
public class enca {public static void main(String[] args) {person a=new person();a.setName("m");String b=a.getName();System.out.println(b);}
}
class  person {String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

这样写get方法和set方法太慢了

我们可以使用快捷键来写alt+ins来找到get和out方法来完成。

这个程序中的age是私有类别,无法访问,极大的保护了用户的隐私。但是如果我是用一个构造器来破解他呢,即为在类中构建一个构造器来修改对象的属性,面对这种情况下的解决方法是,我们可以将这些get和set方法写在构造器当中,就可以实现保护的功能。

比如这样就会失效

package test.encapsulation;
public class enca {public static void main(String[] args) {person smith = new person("smith", 5);String b=smith.getName();System.out.println(b);}
}
class  person {String name;private int age;public person() {}public person(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}
}

继承

继承的含义以及为什么需要继承的存在

在写程序时,如果有两个类,比如说小学生和大学生,这两个类当中有许多属性和方法都是相同的,重复写会显得繁琐,这时候就可以使用继承,来使得程序简化。

当多个类中存在相同的属性和方法时,可以从这些类中抽象出父类,只需要通过extends来声明继承父类即可。

基本语法

class 子类 extends 父类{}
  1. 子类会自动拥有父类定义的属性和方法
  2. 父类又叫超类,基类。
  3. 子类又叫派生类。

快速入门案例

学生考试案例,大学生和小学生有姓名,考试成绩,考试内容三个属性,使用继承来简化代码。

package test.encapsulation;public class student {public static void main(String[] args) {DAStuednt daStuednt = new DAStuednt();daStuednt.name="mike";daStuednt.chanegji=80;XIAOStuednt xiaoStuednt = new XIAOStuednt();xiaoStuednt.name="johb";xiaoStuednt.chanegji=50;daStuednt.Infor();xiaoStuednt.Infor();}
}
class Student{String name;double chanegji;String kemu;public void Infor(){System.out.println("mame="+name+"chanegji"+chanegji+"kemu"+kemu);}
}
class DAStuednt extends Student{String kemu="gao shu";}
class XIAOStuednt extends Student{String kemu="shu xue";
}

好处

  1. 代码的复用性提高了
  2. 代码的扩展性和维护姓提高了

细节深入

  1. 子类继承了父类所有的方法和属性,但是私有属性和方法不能在子类中直接访问,要通过公共的方法去访问。
    比如一个父类中的name属性为私有属性,我们可以在父类中用一个getname的方法返回name的值,通过调用父类的getname方法从而使子类可以使用父类的name属性。相当于一个中转站。

  2. 子类必须调用父类的构造器,完成父类的初始化。
    当创造子类对象时,子类的无参构造器被调用,父类同时也被调用,并且先调用父类的无参构造器,后调用父类的无参构造器。
    因为这其中隐藏了一个super()方法。

    eg:public class sub extends base{public sub(){super();………………}}
    

    这个super()方法就是默认的。

  3. 当创建子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个无参构造器完成对父类的初始化工作,否则,编译不会通过。
    下面我用代码帮助来理解

     public class base{public base(String name) {}}
    public class sub extends base{public sub(){super("mike");}
    }
    

    就是必须在子类构造器中用super方法指定父类构造器,super括号里面写父类构造器的参数。

  4. 如果希望去指定调用父类的某个构造器,则显示的调用一下。
    就是使用super来指定。

  5. super在使用时,需要放在构造器的第一行。

  6. super和this都只能放在构造器的第一行,因此这个两个方法不能共存在一个构造器内。

  7. 使用cutle +h 可以看到所有类的继承关系。

  8. 父类构造器的调用不限于直接父类!将一直往上追溯到顶级父类。

  9. java时单继承机制,即为a不能继承b,再继承c。

  10. 不能滥用继承,子类和父类必须满足逻辑关系。

继承的本质

class GrandPa{String name= "大头爷爷";String hobby="";
}
class Father extends GrandPa{String name="大头爸爸";int age=39;
}
class Son extends Father{String name="大头儿子";
}
Son.son=new Son();

下面我提出三给个问题:

  1. son.name=?
  2. son.age=?
  3. son.hobby=?

我用内存分配来加以理解,代码由创建son对象来开始,对象创建后,会在方法区开辟空间,son的父类为father ,father的父类为grandpa,grandpa没有父类,因此方法区会先开辟grandpa的空间接下来是father最后是son。在堆中开始分配常量空间,会先为grandpa类开辟一个空间来储存常量一个是name,一个是hobby,接下来为father开辟空间进行常量分配,并会不进行覆盖或者冲突。

如果son .属性 这个属性没有在son中定义,就会到son的上一级去找直至找到,但是如果son有这个属性,则会直接输出。如果是父类的私有属性,则不能访问,会报错。如果父类的age是私有的,爷爷类也有age,他不会去输出爷爷的age,而是报错,因为father类的age是私有的,会直接报错,并不会去grandfather查找。

例题

编写Computer类,包含CPU,内存,硬盘等属性,getDetails方法用于返回Computer的详细信息。

编写PC类,继承Computer类,添加特有属性“品牌brand”

编写NotePad子类,继承Computer类,并添加特有属性“演示color”

编写Test类,在main方法中创建PC和NotePad对象,分别给对象中特有的属性赋值,以及从Computer类继承的属性赋值,并使用方法打印输出信息。



这里我用PC类作为例子。

super ()方法

基本介绍

super代表父类的引用,用于访问父类的属性,方法,构造器

基本语法

  1. 访问父类的属性,但不能访问父类的private属性
    super.属性
  2. 访问父类的方法,不能访问父类的private方法
    super.方法名(参数列表)
  3. 访问父类的构造器
    super(参数列表)注意这句只能放在构造器的第一句,只能出现一句。

super给编程带来的便利(细节)

  1. 调用父类构造器的好处(分工明确,父类属性由父类初始化,子类的属性由子类初始化

  2. 当子类中有和父类的属性或方法重名时,为了访问父类的成员属性,必须通过super。如果没有重名,使用super,this,直接访问是一样的效果。
    eg:

    class A{public void say(){System.out.println("A say~~")}
    }
    class B extends A{public void test(){say();this.say();super.say();}
    }
    

    第8 9 10 行都可以调用想要的方法,但是如果有重名的时候出现,他会直接调用本类的,因为在查找方法时,会先找本类,如果没有再去找父类的,当重名情况出现时就得使用super关键字了。this关键字此时是指代本类的,加不加都一样。

    super.say()是直接找父类的,跳过了找本类的这一步。接下来的步骤和找本类的一样进行。

  3. super的访问不限于直接父类,如果爷爷类和本类中有同名的成员,也可以使用super去访问爷爷类的成员,如果多个基类中都有同名的成员,使用super访问遵循就近原则。

方法重写/覆盖(override)

基本介绍

方法覆盖就是子类有一个方法,和父类的某个方法的名称,返回类型,参数一样,那么我们说子类的这个方法覆盖了父类的那个方法

我以一段代码加以理解

class A{public void say(){System.out.println("A")}
}
calss B extends A{public void say(){System.out.println("B");}
}

这里的say方法就构成了方法重写

注意事项

  1. 子类方法的参数,方法名称,要和父类方法的参数,方法名称完全一样

  2. 子类方法的返回类型和父类方法返回类型一样,或者是父类返回类型,是子类返回类型的父类。

    ![微信截图_20230529142555](微信截图_20230529142555.png)public Object getIfor()
    public String getInfor()
    

    这里的object类型是string的子类,因此可以正常运行。

  3. 子类方法不能缩小父类方法访问的权限。
    即为必须遵守public prote 空private的顺序。

    void say()
    private void say()
    

    第一行的访问权限大于第二行的访问权限,所以第一行可以成为第二行的父类,但是第二行不能成为第一行的父类。

练习

编写一个person类,包括属性name age 构造器,方法say(返回自我介绍的字符串)

编写一个student类,继承person类,增加id,score的属性,以及构造器,定义say()方法返回自我介绍的信息。

在main方法中分别创建person和student对象,调用say方法输出自我介绍。

多态


为何提出多态

我用一个案例来来说明,编写一个程序,Master中有一个feed方法,可以完成主人给动物喂食的信息,Master主人类 Food食物类(fish鱼肉类,Bone骨头类,Rice米饭类)Animal动物类(Cat猫类 Dog狗类 Pig猪类)



当养的动物开始增多时,我们会发现main方法的feed方法会越写越多,这样的情况就需要多态出马来解决了。

基本介绍

方法或对象有多种形态,是面向对象的第三大特征,多态是建立在封装和继承的基础之上的

具体体现

  1. 方法的多态,重写和重载就体现出了多态,一个对象通过改变他的形参列表,可以去改变调用的方法。方法形成了重载,具有多种不同的形态。

  2. 对象的多态

    • 一个对象的编译对象和运行类型可以不一致。

    • 编译类型在定义对象时,就确定了,不能改变。

    • 运行类型是可以变化的。

    • 编译类型看定义时=的左边,运行类型看=的右边。

      class Animal{}
      class Dog extends Animal{}
      Animal animal = new Dog();
      

      注意看第七行,animal的编译类型时Animal但是他的运行类型是Dog。

      如果我在第七行后写上一句

      animal=new Cat();
      

      此时的运行类型就是Cat,对象的类型进行了改变。这就被称为**对象的多态**。

案例

以动物喂食为案例,对上面的代码进行优化

只需要修改第一张图片即可

Animal可以指向Animal的所有子类对象,Food可以指向Food的所以子类对象。

注意事项和细节讨论

编译javac 运行java

  1. 前提条件:两个包或者类有着继承关系。

  2. 多态的向上转型

  • 本质:父类的引用指向了子类的对象,比如上面的animal指向了dog
  • 语法:父类类型 引用名 = new 子类类型()
  • 特点
    • 编译类型看左边,运行类型看右边

    • 可以调用父类中的所有成员。(须遵守访问权限)

    • 不能调用子类中的特有成员。

    • 最终运行效果看子类的具体实现。

      即调用方法时,从子类开始找,没有了找父类。

  1. 多态的向下转型
  • 语法:子类类型 引用名 =(子类类型)父类引用;

  • 只能强转父类的引用,不能强转父类的对象

  • 要求父类的引用必须指向是当前目标类型的对象。

  • 可以调用子类类型的所有成员。

  • 例子

    希望调用cat的catchmouse方法class Cat extends Animal{public void catchmouse(){System.out.println("get mouse");}}Cat cat=(Cat) animal;cat.catchmouse();
    
    Cat cat=(cat) animal;
    Dog dog=(Dog) animal;
    

    第二个代码块的第二行会出错(类错误),因animal是指向猫的对象。第二行将其强制转换为狗,出现了错误。

  1. 属性没有重写之说,属性的值看编译类型。

    class Base{int count = 10;
    }
    class Sub extends Base{int count =20;
    }
    Base base =new Sub();
    base.count;
    

    这里的第八行的值是10,因为他的编译类型为base,会直接从base中的对象开始查找,找i到后直接输出。
    左边是编译类型

  2. instanceOf 比较操作符
    用于判断对象的类型是否为XXX类型或者XXX类型的子类。

    class A{}
    class extends B{}
    class c{}
    B b=new B();
    C c=new C();
    C a=new b();
    System.out.println(b instanceof A);
    System.out.println(c instanceof A);
    System.out.println(a instanceof A);
    

    第一个返回true,第二个返回false,第三个返回true。综合第一个和第三个来看,这个方法比较的是运行类型,而不是编译类型。

练习

写出下面代码的输出结果。

class Base{int count =10;public void display(){System.out.println(this.count);}
}
class Sub extends Base{int count=20;public void display(){System.out.println(this.count);}
}
Sub s=new Sub();
System.out.println(s.count);
s.display();
Base b=s;
System.out.println(b==s);
System.out.println(b.count);
b.display;

分析

​ 首先第十三行创建了Sub的对象s,所以s所使用的属性都是Sub中的。

​ 然后将b指向了s,实现了向上转型,b和s共同指向同一个地址,即为Sub的地址。

​ 此时的b的编译类型为Base 运行类型为Sub。

答案

​ 20 20 true 10 20

这个10和20,是因为程序运行过程中,属性看编译类型,方法看运行类型

应用

多态数组

数组的定义类型为父类类型,里面实际保存的类型为子类类型

实际应用

现有一个继承结构,Student和Teacher为Person的子类。现要求创建一个Person对象和两个Teacher对象,统一放在数组中,并且调用每个对象的say方法。



多态参数

方法定义的形参为父类类型,实参类型允许为子类类型

应用实例

定义员工类Employee,包含姓名和月工资,以及计算年工资getAnnual的方法,普通员工和经理继承了员工,经理类多了奖金bonus属性和管理manage方法,普通员工多了work方法,普通员工和经理类要求重写agtAnnual方法


最后text类中的getmoney方法中的参数就为多态参数,可以改变运行参数从而调用想要的方法。

Java的动态绑定机制

特点

  1. 当调用对象方法的时候,该方法会和该对象的内存地址/与运行类型绑定。
  2. 当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。

实例

class A{public int i=10;public int sum(){return get()+10;}public int sum1(){return i+10;}public int get1(){return i;}
}
class B extends A{public int i=20;public int sum(){return i+20;}public int get(){return i;}public int sum1(){return i+10;}
}
main方法中
A a=new B();
System.out.println(a.sum());
System.out.println(a.sum1());

首先将a指向B类,实现向上转型,此时a的运行类型为B,编译类型为A。第一个输出语句中调用方法,看运行类型,所以输出的是40,第二个同理输出30。

但是我现在如果将B类中的sum和sum1方法注销,这两句的输出又是什么呢?
将B类的方法注销后,找不到方法,会去父类A查找,此时调用了A的sum方法,sum方法中又有get方法,那么此时到底是调用A中的方法还是B的方法呢?
根据Java的动态绑定机制,当调用对象方法的时候,该方法会和该对象的内存地址/与运行类型绑定,此时对象的运行类型为B,会和B类的get方法绑定,因此调用了B类中的get方法,输出了30。

运行sum1方法时,因为B被注销,无法查找到,会去A进行查找,调用a的sum1方法,此时的i根据Java的动态绑定机制第二条当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。这里的就是A中的i,所以输出了20。

Object类详解

Object类再java的lang包中,是自动引用的,程序中的所有对象都可以调用这个类中的方法

equals方法

equals和==的对比
  1. ==:既可以判断基本类型,又可以判断引用类型

    • 如果判断基本类型,判断是值是否相等。
    • 如果判断引用类型,判断的是地址是否相等,即为判断是不是同一个对象。

Java中的方法

Scanner方法

  • 导入该方法库

    • import Java.util.Scanner;
  • 新建一个对象,来接收这个方法

    • 使用到new()

    • Scanner A=new Scanner(System.in)

  • 看需要从键盘输入哪些类型,来确定下面的方法,我用int为例子

    • int a=A.nextInt();
  • 接下来从键盘输入即可。

  • 字符串输入时使用A.next()方法

随机方法(Math.random)

  • math库中的random方法,这个方法可以返回0.0到1.0之间的double类型数字。

  • eg:如果我想随机0~100之间的随机数字

    • int a=Math.random()*100+1

    • 写出上面的代码即可

标签的使用(label)通常和break和continue一起使用。

  • 标签的名称由程序员定义。
  • 标签在实际开发中尽量不要使用。
  • break后的标签是什么,就退回到那个标签后的循环体。
  • 如果break后面没有指定,就退出到最近的循环体。

string中的equals方法(比较字符串是否相同)

  • 用于将字符串进行比较,返回boll值。

  • 比如

    - String name="mike";System.out.print(name.equals("nike"));
    -
    
  • 这个程序执行完后会返回一个false值。

计算数组长度的方法(length方法)

使用数组名称.length可以得到数组的长度

hashCode()方法【可以查询地址】

使用这个该方法,可以返回一个哈希码值,这个哈希码是根据该对象的地址进行变化得出的,可以变相的进行地址的比较。

排序

分类

  • 内部排序

    • 指将需要处理的所有数据都加载到内部储存器进行排序,包括交换式排序法,选择式排序法和插入式排序法。
  • 外部排序
    • 指数据量过大,无法全部加载到内存中,需要借助外部储存进行排序,包括合并排序法和直接合并排序法。

冒泡排序

  • 进行多轮比较,将大数放到小数的后面。 (进行数字数目减一次)

    • 第一轮比较会将最大的数字移动到最后一位

    • 第二轮比较会将第二大的数组移动到倒数第二位,在比较时,因为第一大的数已经确定下来了,所以没有和最后一个比较的必要

    • 综上所述,比较的轮数是数字数目总和减一

public class MaoPao {public static void main(String[] args) {int a[] = {5, 8, 4, 9, 55, 47, 1, 0};for (int j = 0; j < a.length - 1; j++) {for (int i = 0; i < a.length - 1- j; i++) {int temp = 0;if (a[i] > a[i + 1]) {temp = a[i + 1];a[i + 1] = a[i];a[i] = temp;}}}for (int s = 0; s < a.length; s++) {System.out.print(a[s]+" ");}}
}

,看运行类型,所以输出的是40,第二个同理输出30。

但是我现在如果将B类中的sum和sum1方法注销,这两句的输出又是什么呢?
将B类的方法注销后,找不到方法,会去父类A查找,此时调用了A的sum方法,sum方法中又有get方法,那么此时到底是调用A中的方法还是B的方法呢?
根据Java的动态绑定机制,当调用对象方法的时候,该方法会和该对象的内存地址/与运行类型绑定,此时对象的运行类型为B,会和B类的get方法绑定,因此调用了B类中的get方法,输出了30。

运行sum1方法时,因为B被注销,无法查找到,会去A进行查找,调用a的sum1方法,此时的i根据Java的动态绑定机制第二条当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。这里的就是A中的i,所以输出了20。

Object类详解

Object类再java的lang包中,是自动引用的,程序中的所有对象都可以调用这个类中的方法

equals方法

equals和==的对比
  1. ==:既可以判断基本类型,又可以判断引用类型

    • 如果判断基本类型,判断是值是否相等。
    • 如果判断引用类型,判断的是地址是否相等,即为判断是不是同一个对象。

Java中的方法

Scanner方法

  • 导入该方法库

    • import Java.util.Scanner;
  • 新建一个对象,来接收这个方法

    • 使用到new()

    • Scanner A=new Scanner(System.in)

  • 看需要从键盘输入哪些类型,来确定下面的方法,我用int为例子

    • int a=A.nextInt();
  • 接下来从键盘输入即可。

  • 字符串输入时使用A.next()方法

随机方法(Math.random)

  • math库中的random方法,这个方法可以返回0.0到1.0之间的double类型数字。

  • eg:如果我想随机0~100之间的随机数字

    • int a=Math.random()*100+1

    • 写出上面的代码即可

标签的使用(label)通常和break和continue一起使用。

  • 标签的名称由程序员定义。
  • 标签在实际开发中尽量不要使用。
  • break后的标签是什么,就退回到那个标签后的循环体。
  • 如果break后面没有指定,就退出到最近的循环体。

string中的equals方法(比较字符串是否相同)

  • 用于将字符串进行比较,返回boll值。

  • 比如

    - String name="mike";System.out.print(name.equals("nike"));
    -
    
  • 这个程序执行完后会返回一个false值。

计算数组长度的方法(length方法)

使用数组名称.length可以得到数组的长度

hashCode()方法【可以查询地址】

使用这个该方法,可以返回一个哈希码值,这个哈希码是根据该对象的地址进行变化得出的,可以变相的进行地址的比较。

排序

分类

  • 内部排序

    • 指将需要处理的所有数据都加载到内部储存器进行排序,包括交换式排序法,选择式排序法和插入式排序法。
  • 外部排序
    • 指数据量过大,无法全部加载到内存中,需要借助外部储存进行排序,包括合并排序法和直接合并排序法。

冒泡排序

  • 进行多轮比较,将大数放到小数的后面。 (进行数字数目减一次)

    • 第一轮比较会将最大的数字移动到最后一位

    • 第二轮比较会将第二大的数组移动到倒数第二位,在比较时,因为第一大的数已经确定下来了,所以没有和最后一个比较的必要

    • 综上所述,比较的轮数是数字数目总和减一

public class MaoPao {public static void main(String[] args) {int a[] = {5, 8, 4, 9, 55, 47, 1, 0};for (int j = 0; j < a.length - 1; j++) {for (int i = 0; i < a.length - 1- j; i++) {int temp = 0;if (a[i] > a[i + 1]) {temp = a[i + 1];a[i + 1] = a[i];a[i] = temp;}}}for (int s = 0; s < a.length; s++) {System.out.print(a[s]+" ");}}
}

从0开始的Java基础,包你学会。相关推荐

  1. java 基础包的功能_Java 8的功能基础

    java 基础包的功能 Java 8彻底改变了Java. 它很可能是过去10年中最重要的Java版本. 有很多新功能,包括默认方法,方法和构造函数引用以及lambda, 仅举几例 . 更有趣的功能之一 ...

  2. java基础包的基本信息_JAVA 基础 之 基本数据类型、引用类型和包...

    java中数据类型有两类 基本数据类型 引用类型 基本数据类型 整数型 byte - 8bit short - 16bit int - 32bit long - 64bit [赋值时一般在数字后加上* ...

  3. 本人初学时java基础笔记

    编程思想 先有面向过程编程思想,后有面向对象编程思想 面向过程的编程思想 面向过程就是,一个过程化的代码,一个流程,比如:电脑先开机,鼠标移动,双击游戏,再玩游戏. 面向对象的编程思想 什么是面向对象 ...

  4. 一个计算机专业学生几年的编程经验汇总 (该系列一共 11 篇,看完之后,java 基础绝对有不小的提升!)

    Java 杂谈(一) 想来学习 Java 也有两个年头了,永远不敢说多么精通,但也想谈谈自己的感受,写给 软件学院的同仁们,帮助大家在技术的道路上少一点弯路.说得伟大一点是希望大家为软件 学院争气,其 ...

  5. Java工程师成神之路java基础知识之集合类(二)

    Java 8中Map相关的红黑树的引用背景.原理等 HashMap的容量.扩容 很多人在通过阅读源码的方式学习Java,这是个很好的方式.而JDK的源码自然是首选.在JDK的众多类中,我觉得HashM ...

  6. java里有没有 0的使用_请问有没有人有零基础Java基础习题?

    第一组: 1.下面哪些是合法的变量名? A(2variable //不能以数字开头 B. (variable2 //不能用点和空格 //不能用点和空格 C. (_whatavariable D(_3_ ...

  7. JavaSE入门0基础笔记 第二章Java基础语法

    JavaSE入门0基础笔记 第二章Java基础语法 1.运算符 1.1算术运算符 1.1.1运算符和表达式 1.1.2 算术运算符 1.1.3字符的"+"操作 1.1.4 字符串中 ...

  8. Java基础以及变量和运算符、包机制、javadoc生成

    Java基础以及变量和运算符.包机制.javadoc生成 注释.标识符.关键字 注释 标识符 关键字 标识符注意点 数据类型 强类型语言 弱类型语言 Java的数据类型 基本类型(primitive ...

  9. Java基础-Eclipse第三方安装包管理工具之Maven

    Java基础-Eclipse第三方安装包管理工具之Maven 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 玩过Linux的小伙伴应该都知道yum吧,我们只要把搭建好的yum仓库配 ...

最新文章

  1. Gear 360新款发布!预购有礼哦
  2. 【Python-ML】SKlearn库特征选择SBS算法
  3. mysql 全文检索 教程_MySQL:详细说明MySQL全文检索图文详细教程
  4. 大道至简,阿里巴巴敏捷教练的电子看板诞生记
  5. 在.NET Core中处理一个接口多个不同实现的依赖注入问题
  6. python大文件排序_python实现按创建时间对文件排序
  7. Golang 垃圾回收机制
  8. 操作系统锁的实现方法有哪几种_一文带你彻底了解同步和锁的本质
  9. 【kafka】Timeout of 60000ms expired before the position for partition could be determined
  10. python调用图灵api_python调用API实现智能回复机器人
  11. overflow c语言_C语言表结构(一)
  12. trie树的数据结构_C / C ++中的Trie数据结构
  13. js 面向对象 继承
  14. 阿里实习 90 天:从实习生的视角谈谈个人成长
  15. 你每天走的步数,手机是怎么算出来的?
  16. (十四)STM32——外部中断(EXTI)
  17. BI数据分析从业者从零开始学习财务知识?有哪些入门书籍推荐
  18. Vue非父子组件传值+案例cnode首页
  19. win ce车载系统刷机包_Android 11 喜讯!小米 10 率先尝鲜,官方刷机包发布下载
  20. 【jQuery】网页文本格式编辑器xheditor

热门文章

  1. java 日期类Date插入mysql数据库时间总是比参数时间少一天
  2. 10大免费FLV播放器下载(转)
  3. JS自制简易版数字华容道小游戏
  4. JS函数式编程【译】5.3 单子 (Monad)
  5. BUUCTF之Had a bad day
  6. Ping域名的时候出现ping:unknown host xxx.xxx
  7. 应用宝上架审核要求_APP开发好后如何上架应用宝?需要准备哪些资料?
  8. 正则表达式,不包含某特殊符号
  9. 软硬件运维主要包括哪些个方面 需要注意哪些关键问题,一共八百字
  10. 传输TCP/IP数据