文章目录

  • 第2章 从C过渡到Java
  • 2.0 本章方法学导引
  • 2.1 快速入门
  • 2.1.1 Java类型概述
  • 2.1.2 输出英文希腊字母、九九乘法表
  • 2.2.2 入门示例l:累加求合
  • 2.1.3 理解类和对象
  • 2.1.4 顺序表及其应用
  • 2.1.4.1 顺序表示例
  • 2.1.4.2 顺序表合并
  • 2.1.5 单链表及其应用类
  • 2.2 强化实践
  • 2.2.1 二叉树及其应用
  • 2.2.2 树及其应用
  • 2.2.3 班级管理系统1.0
  • 2.3 从内存管理视角观察程序
  • 2.4 班级信息管理系统2.0版
  • 2.4.1 输入输出格式化、日期、读文件
  • 2.4.2 学生数组的两种排序方式
  • 2.5 一些工具类的使用
  • 2.6 综合示例
  • 2.7 本章小结


第2章 从C过渡到Java

2.0 本章方法学导引

2.1 快速入门

2.1.1 Java类型概述

java中layout用法 javayouth_java

引用型只能按名引用(类似更换"值日生"袖标,贴在张三、李四上),不能偏移(C指针可偏移,即指针值++、–)。

另外,引用型必须要关联一个==被引用的对象,==引用才有意义。

2.1.2 输出英文希腊字母、九九乘法表

class W2{//功能:打印英文字母、希腊字母、九九乘法表
    //类W2只有两个成员(即两个函数/方法)
    int x=5;
    void prnEnChar(){//字面量
        for(char i='a';i<='z';i++)
            //System.out.print(i+'');//打印出一组数字,是因为:x+""==>产生字符串的连接,如'a'+" "==>"a" 'a'+' '==>Unicode字符'a'(无符号整数)+''(无符号整数)==>新的无符号整数
            System.out.print(i+" ");//"123"+"abc"结果为123abc
        x=x+5; System.out.print("\n x="+x+"\n ");//测试属性是所有方法的全局变量
        
    }
    void prnjj(){
        for(i=1;i<=9;i++){
            for(int j=1;j<=i;j++)
                System.out.printf("%d*%d=%2d ",i,j,i*j);
            System.out.printf("\n");//System.out.println();//ln表示line
        }
    }
}
class App{
    public static void main(String[] args){
        W2 w=new W2();//调用函数,必须先造对象
        w.prnEnChar()
    }
}
//1.通过上述编程,发现C的语法几乎都能直接使用,例外:打印System.out、main、所有东西都必须包在class里面;【【【重要:必须先造对象,再调用其方法

2.2.2 入门示例l:累加求合

与C程序相比,Java程序有一些不同

  1. ***类是Java程序的基本结构。***类的基本框架为:class 类名{类体},类体由一组变量、函数组成,均称作类的成员,其中变量也称作属性,函数也称作方法/行为。如Ch_2_1有3个成员:成员变量maxN,成员方法sum()和main()。

#成员变量和局部变量的作用域不同。

成员变量定义在类中、方法外,相当于方法的外部变量,故作用域是整个类,可直接应用于该类的成员方法。注:因main前有static修饰,故不可直接使用maxN。

#成员方法:函数的返回类型需于返回值保持一致。
2. ***组成标识符的字母范围更广。***标识符就是程序员为变量/常量、函数、类等起的名字。Java 标识符由字母、数字、下划线、货币符等字符组成,数量不限,其中数字不可作为第一个字符。关键字是语言中有特殊意义的单词,不能用作标识符。

java中layout用法 javayouth_System_02

  1. 输出语句不同。
    System.out.printf(…)
  2. ***调用函数的方式不同。***必须先基于类创建对象,然后基于对象调用函数。例如:
    Ch_2_1 c=new Ch_2_1();//用new 类名()创造对象
    c.sum(10);//用 对象名.函数名(实参列表); 的方式调用函数。
  3. main() 的书写方式不同。
    main()依旧是执行程序的入口,但书写格式固定:public static void main(String[] x){…}

2.1.3 理解类和对象

2.1.4 顺序表及其应用

  1. 认识Java的数组类型
    (1)Java用方括号[]来标记数组,例如:
    int [] a,b;//a、b是int[]型变量。==注:定义时不能指定容量,==如int[3]a;会报错。
    (2)必须先创建数组对象,才能引用其元素,如:
    a=new int[10]; //创建数组a引用的对象
    a[0]=5; //给数组元素赋值
    b[0]=3; //编译错,因为b并未关联数组对象,b[0]不存在。
    (3)可以在定义时创建或初始化数组对象,如:
    int [] c=new int [20];
    int [] d={1,2,3,4,5}
    (4)每个数组对象都有一个常量属性length,用于记录数组的容量。如:a.length、d.length的值分别是10、5.
  2. 理解输入类Scanner
    (1)使用前必须导入Scanner类,即在文件头部增加语句:import java.until.Scanner;
    (2) 创建Scanner对象方式为: Scanner sc=new Scanner(System.in);
    System.in代表标准输入设备,即键盘。这样通过键盘的所有输入都可从读取。数据间默认用空格分隔。
    (3)读取int型数据的方式为 : int x=sc.nextInt();
    说明:类似地,nextDouble()、nextBoolean()可以读取double、boolean型数据。
  3. 构造和使用顺序表
    从构造角度看,顺序表=数组+表长+操作集,其中数组提供顺序存储空间,表长框定数组存储数据的范围,至于操作集,可根据需要灵活定义。

2.1.4.1 顺序表示例

【例2.3】设计存储int型元素的顺序表类Seqlist。要求:顺序表的最大容量在创建顺序表对象时指定;包含从尾部追加、输出表中全部数据、插入元素至指定位置、排序等基本操作。

import java.util.Scanner;//导入Scanner类,旨在告诉编译器:Scanner的位置
 //换言之,在本文件的其他地方,可以直接写Scanner,而不是写其全名:java.util.Scanner
 class Seqlist{//顺序表=数组+表长+操作集 数组有容量,相当于有容量,表长即教室的实际人数
     int [] a=new int [100];//定义数组,a的类型是int[].java中的数组对象是new出来的
    
     int len;//成员变量虽然没有赋值,但在对象构造时,均自动赋予默认值
     //数值型默认值均为0,引用型均为null,boolean默认值均为false
     //猜测所有类均有构造函数,(自己定义或编译系统自动给出。而构造函数的作用是初始化)
     //注意:局部变量没有默认值
     
      //新需求:要求在顺序表构造时之doing容量
     Seqlist(int max){a=new int[max];}//注意,用的是方括号,即未调用构造函数
     //即new int [max]造的是数组对象,该对象内有max个元素空间
    void append(int x){//向数组尾部追加元素 1 2 3 4 
        a[len]=x;len++;//修改表长   
     }
     void insert(int x,int pos){//在pos处插入x
         for(int j=len-1;j>=pos;j--)
             a[j+1]=a[j];
         a[pos]=x;
         len++;
         
     }
     void show(){//输出顺序表中的所有元素
     //void show(Seqlist *L)
         for(int i=0;i<len;i++)
             System.out.print(a[i]+" ");
     }//前万不能孤立的看一个方法,方法执行时,还要考虑其调用者,如main中的s.show、s1、show,调用者不同,调用者内部嵌入的数组也就不同。
     void sort(){
         java.util.Arrays.sort(a,0,len);
     }
 }
 class App{
     public static void main(String[] args){
         Seqlist s=new Seqlist(100);
         Seqlist s1=new Seqlist(100);
         Scanner sc=new Scanner(System.in);//其中System.in代表标准输入设备--键盘
         int x;System.out.println("请输入一组数,以0结束:");
         x=sc.nextln();//从SC中读取一个int型数据
         while(x!=0){s.append(x);x=sc.nextlnt();}
         //for(int i=0;i<10;i++)s.append(i);
         s.show();
         System.out.printIn();
         System.out.println("向s中0、2、5处插入11、22、99");
         s.insert(11,0);s.show();System.out.printIn();
         s.insert(22,2);s.show();System.out.printIn();
         s.insert(99,5);s.show();System.out.printIn();
         s.sort();
         System.out.printIn();
         s.show();        
         //System.out.printIn("S1=");s1.show();System.out.println("##");
         //System.out.printIn();
     }
 }

小结:注意show()、append()无参,输入的数据直接存于数组a中(前提:a必须new出对象)。

插入三步走:第一步:先移出空位(从哪里开始,到哪里结束,如何移,移动哪些元素),第二步:实施插入a[pos]=x,第三步:修改表长:len++。

排序java.util.Arrays.sort(a,0,len);

2.1.4.2 顺序表合并

【例2.4】在例2.3的基础上,实现将两个升序表合并成新的升序表。

分析:涉及到两个对象的操作。合并:创建新表,合并到新表中,尾表的处理

import java.util.Scanner;
  class Seqlist{
      int [] a=new int [100];int len;
      Seqlist(int max){a=new int[max];}
      void append(int x){a[len]=x;len++;}
      void show(){for(int i=0;i<len;i++)System.out.print(a[i]+" ");}
      void create(){
          Scanner sc=new Scanner(System.in);
          int x;System.out.println("请输入一组数,以0结束");
          x=sc.nextInt();
          while(x!=0){append(x);x=sc.nextlnt();}//注意:调用自己的方法this.append();
      }
      
      Seqlist merge(Seqlist L1,Seqlist L2){//升序表L1+升序表L2==》升序表返回
          Seqlist L=new Seqlist(100);
          int i,j,k;i=0;j=0;k=0;
          while(i<L1.len&&j<L2.len)//实施两个表的比较,小者放入新表
              if(L1.a[i]<L2.a[j]){ L.a[k]=L1.a[i];i++;k++;}
          else{L.a[k]=L2.a[j];j++;k++;}
          while(i<L1.len){L.a[k]=L1.a[i];i++;k++;}
          while(j<L2.len){L.a[k]=L2.a[j];j++;k++;}
          L.len=L1.len+L2.len;
          return L;  
      }
      
       Seqlist merge(Seqlist L1){//升序表L1+升序表this==》升序表返回//this是每个对象自带的常量引用
          Seqlist L=new Seqlist(100);
          int i,j,k;i=0;j=0;k=0;
          while(i<L1.len&&j<this.len)//this也可省略
              if(L1.a[i]<a[j]){ L.a[k]=L1.a[i];i++;k++;}//此处a[j]实际上是this.a[j]
          else{L.a[k]=this.a[j];j++;k++;}
          while(i<L1.len){L.a[k]=L1.a[i];i++;k++;}
          while(j<len){L.a[k]=a[j];j++;k++;}
          L.len=L1.len+len;
          return L;  
      }
      
      void merge1(Seqlist L1){//升序表L1+升序表this==》升序表返回//this是每个对象自带的常量引用
          //Seqlist L=new Seqlist(100);
          int [] x=new int[100];
          int i,j,k;i=0;j=0;k=0;
          while(i<L1.len&&j<this.len)//this也可省略
              if(L1.a[i]<a[j]){ x[k]=L1.a[i];i++;k++;}//此处a[j]实际上是this.a[j]
          else{x[k]=this.a[j];j++;k++;}
          while(i<L1.len){x[k]=L1.a[i];i++;k++;}
          while(j<len){x[k]=a[j];j++;k++;}
          len=L1.len+len;//或者 this.len=L1.len+len
          this.a=x;//或者a=x;
         // return L;  
      }   
      
  }
   class App{
       public static void main(String[] args){
           Seqlist s1=new Seqlist(100);Seqlist s2=new Seqlist(100);
           s1.create();s2.create();
           System.out.println("S1:");s1.show(); System.out.print("\n");
           System.out.println("S2:");s2.show(); System.out.print("\n");
           //Seqlist s3=s1.merge(s1,s2);
           //Seqlist s3=s1.merge(s2);
           s1.merge1(s2);
           System.out.println("S1:");s1.show(); System.out.print("\n");
       }
  }                   //this的理解要结合调用来进行:a.merge(b);此时,merge(...)中的this指代a;b.merge(a);
                                         //此时,merge(...)中的this实际上指代b;

重载:可以函数同名不同参 对象的替换只要更改指针的值即可。注:this的理解要结合调用来进行a.merge(b)此时merge(…)中的this指代a;b.merge(a),此时erge(…)中的this实际上指代b。

2.1.5 单链表及其应用类

单链表=数据域+next指针+操作集。

所有引用成员都有默认值,可以省略。

头结点:指向线性表中第一个元素的第一个元素的结点;

头指针:指向线性表的第一个元素的指针。

import java.util.Scanner;
class LinkedList{
    int data;LinkedList next;
    LinkedList(int x){ data=x;}//next=null;
    //LinkedList(){;}同名不同参,即函数重载
    void create(){
        Scanner sc= new Scanner(System.in);
        int x;
        LinkedList tail,q;
        System.out.print("input: ");
        x=sc.nextInt();tail=this;//h.create()就是h,即头结点   
        while(x!=0){//造结点、把结点插入表尾、修改表尾、再读一个数据
            q=new LinkedList(x);
            tail.next=q;
            tail=q;
            x=sc.nextInt();
    }
    void show(){
        LinkedList p;
        for(p=this.next;p!=null;p=p.next)
            System.out.print(p.data+" ");
    }
    
    LinkedList createNoHead(){//用尾插法创建单链表--头指针型
        Scanner sc= new Scanner(System.in);
        int x;LinkedList h,tail,q;
         System.out.print("input: ");
        //先特别处理第一个元素,即建立表头
        x=xc.nextInt();
        if(x==0)return null;
        h=new LinkedList(x);
        x=sc=nextInt();tail=this;//h.create()就是h,即头结点
        while(x!=0){//造结点、把结点插入表尾、修改表尾、再读一个数据
            q=new LinkedList(x);
            tail.next=q;
            tail=q;
            x=sc.nextInt();
    }
        return h;
    
    void showNoHead(){
        LinkedList this;
        for(p=this.next;p!=null;p=p.next)
            System.out.print(p.data+" ");
    }
        
    void delAll(int x){//删除链表中所有值为x元素//双指针移动
        LinkedList pre,p;
        pre=this;p=this.next;
        while(p!=null){
            if(p.data!=x){p=p.next;pre=pre.next;}//或者写成:pre=p;p=p.next;
            else{p=p.next;pre.next=p;}
        } 
    }
}
class App{
    public static void main(String[] args){
        LinkedList h=new LinkedList(0);
        //h.create();h.show();
        h=h.createNoHead();//h可能为null,从而在h.delAll()、h.show()处引发空指针引用异常
        System.out.print("删除所有的1,结果为:\n");
        h.delAll(1);
    }   
}

注:没写构造函数,系统会给你补一个无参的构造函数,一旦写了,系统将不会给你补构造参数。//方法一:LinkedList(0);方法二:LinkedList(){;}同名不同参,即函数重载

2.2 强化实践

2.2.1 二叉树及其应用

java中layout用法 javayouth_开发语言_03

import java.util.Scanner;
//按需造类
class ReadChar{//专门用于给建树提供getchar()操作
    String data;//存储建树用的字符串
    int pos=-1;//指向当前应读的字符
    ReadChar(String x){data=x;}
    char getChar(){pos++;return data.charAt(pos);}//不能return data[pos];String的方法CharAt
    
}
class BTree{
	char data;BTree L,R;
	BTree(char x){data=x;}
	BTree(){;}
	//BTree create(ReadChar r){
    static BTree create(ReadChar r){//静态方法的特色:可不造对象,直接通过类名使用
	char x=r.getchar();
	if(x=="#")return null;
	BTree t=new BTree(x);
	t.L=create(r);t.R=create(r);
	return t;
	}
    
    void pre(){//C的方式pre(t);==>Java方式:t.pre();
        //this一定不为空,this代表对象this=t;
        System.out.print(this.data+" ");
        //this.L.pre.();this.R.pre();//注:此处可能发生空指针引用,因为this.L或this.R可能为空
        if(this.L!=null)L.pre();
        if(this.R!=null)R.pre();
    }
    class Stack{//内部类,实际上是类中作为类型的成员
        BTree[]data=new BTree[20];
        int top;
        void init(){top=0;}
        boolean isEmpty(){return top==0;}
        void push(BTree x){data[x]=x;top++}
        BTree pop(){top--;return data[top--]; }
      
    }
    void preN(){
        class Stack{}//可以,类,本质上就是类型,Stack定义在preN()中,即其作用域仅限于preN()
        Stack st=new Stack();
        BTree t=this;
        while(t!=null||st.isEmpty()==false){
            if(t!=null){
                System.out.print(this.data+" ");//此句有误
                System.out.print(t.data+" ");
                st.push(t);t=t.L;}
            else{
                t=st.pop();t=t.R;
            }
        }
    }
    void inN(){
        class Stack{}//可以,类,本质上就是类型,Stack定义在preN()中,即其作用域仅限于preN()
        Stack st=new Stack();
        BTree t=this;
        while(t!=null||st.isEmpty()==false){
            if(t!=null){
                System.out.print(this.data+" ");//此句有误
                //System.out.print(t.data+" ");
                st.push(t);t=t.L;
             }
            else{
               t=st.pop(); System.out.print(t.data+" ");t=t.R;
            }
        }
    }
    
    
    void in(){
       if(this.L!=null)L.in();
       System.out.print(this.data+" ");
       if(this.R!=null)R.in();
    }    
    void post(){
       if(this.L!=null)L.post();
       if(this.R!=null)R.post();
        System.out.print(this.data+" ");  
    }
}

class App{
    public static void main(String[] args);
   // BTree t=new BTree();
    Scanner r=new Scanner(System.in)
    System.out.print("请输入建树数据,#表示null:\n")
    String x=sc.nextLine();//next读到空格时停下
    ReadChar r=new ReadChar(x);
    //t=t.create(r);//实际上,t原来的对象就被扔掉了
    BTree t=BTree.create(r);
    System.out.print("\n pre: ");t.pre();
    System.out.print("\n preN: ");t.preN();
    System.out.print("\n in: ");t.in();
    System.out.print("\n inN: ");t.inN();
    System.out.print("\n post: ");t.post();
    
}

//建树即造根,通过造一个类来输入字符。

//二叉树的前序遍历非递归算法,进入左子树前需保存当前结点供遍历右子树之用。关键:何时保存、何时用、何时删除回溯点。
/*preOrder(btree *t){
    initStack(S);
    while(t不空||栈不空)
    {
        if(t不空){
            访问t;//访问根
            保留回溯点;
             t=t->L;//访问左子树
        }
        else{
            t=回溯点;
            删除回溯点;
            t=t->R;//访问右子树
        }
    }
}*/
preOrder(btree *t){
    Stack S;
    initStack(&S);
    while(t!=NULL||栈不空)
    {
        if(t!=NULL){
            V(t);
            push(&S,t);t=t->L;
        }
        else{
            t=pop(&S);
            t=t->R;
        }
    }    
}

2.2.2 树及其应用

java中layout用法 javayouth_c语言_04

【例】:设计能存储char型数据的链式K叉树结构,并实现前/后序的递归/非递归遍历。

import java.util.Scanner;
//按需造类
class ReadChar{//专门用于给建树提供getchar()操作
    String data;//存储建树用的字符串
    int pos=-1;//指向当前应读的字符
    ReadChar(String x){data=x;}
    char ReadChar(){pos++;return data.charAt(pos);}//不能return data[pos];String的方法CharAt
    
}
class KTree{  final int k=3;//成员常量只有两处可以赋值:1、定义时用=赋值,如k=3;2、在构造函数中赋值
	char data;int tag;KTree[] c=new KTree[k];
	KTree(char x){data=x;}
	KTree(){;}
	//KTree create(ReadChar r){
     KTree create(ReadChar r){//静态方法的特色:可不造对象,直接通过类名使用
	char x=r.Readchar();
	if(x=="#")return null;
	KTree t=new KTree(x);
	for(int i=0;i<k;i++);t.c[i]=create(r);
	return t;
	}
    
    void pre(){
        System.out.print(this.data+" ");
        for(int i=0;i<k;i++)if(c[i]!=null)c[i].pre();
    }
    void post(){
         for(int i=0;i<k;i++)f(c[i]!=null)c[i].post();
         System.out.print(this.data+" ");
    }
    class Stack{//内部类,实际上是类中作为类型的成员
        KTree[]data=new KTree[20];
        int top;
        void init(){top=0;}
        boolean isEmpty(){return top==0;}
        void push(KTree x){data[x]=x;top++;}
        KTree pop(){top--; return data[top--]; }
        KTree getTop(){ return data[top-1]; }
    }
    void preN(){Stack st=new Stack();KTree t=this;
                st.push(t);
                while(st.isEmpty()==false){
                    t=st.getTop();
                    if(t==null)st.pop();
                    else if(t.tag==0){
                        System.out.print(t.data+" ");st.push(t.c[0]);t.tag++;}
                    else if(t.tag<k){st.push(t.c[t.tag];t.tag++;)}
                    else if(t.tag==k)st.pop();
                }
}
}
class App{
    public static void main(String[] args){
    KTree t=new KTree();
    Scanner r=new Scanner(System.in);
    System.out.print("请输入建树数据,#表示null:\n");
    String x=sc.nextLine();//next读到空格时停下
    ReadChar r=new ReadChar(x);
    t=t.create(r);//实际上,t原来的对象就被扔掉了
    //KTree t=KTree.create(r);
    System.out.print("\n pre: ");t.pre();
    System.out.print("\n preN: ");t.preN();
    System.out.print("\n post: ");t.post();
    System.out.print("\n");
	}
}

//28:03

==成员常量只有两处可以赋值:==1、定义时用=赋值,如k=3;2、在构造函数中赋值。

java中layout用法 javayouth_System_05

2.2.3 班级管理系统1.0

2.3 从内存管理视角观察程序

java中layout用法 javayouth_java_06

对象如何关联到方法:就数据存储而言,栈中存储函数中定义的变量,堆中存储动态创建的对象;方法区中存储运行期间动态加载的数据类型。

java中layout用法 javayouth_System_07

编译期间能确定的,统称静态…,运行期间确定的,统称动态…

基于栈、堆的内存管理:

1、栈内存管理(静态/自动内存管理):涉及函数中定义的所有变量

2.堆内存管理(动态/手动内存管理):涉及运行期间创建的所有对象。

2.4 班级信息管理系统2.0版

2.4.1 输入输出格式化、日期、读文件

format()效果与printf()几乎相同,只不过后者是打印输出,而前者是返回格式化之后的字符串。

class Test{
    public static void main(String [] x){
        String s;
        System.out.print("1234567890");
        s=String.format("%5s","001");
        System.out.print("\n"+s);
        s=String.format("%-5s","001");
        System.out.print("\n"+s);
        s=String.format("%3.2f","12.345");//总长度不足,以实际长度为准,结果为12.35
        System.out.print("\n"+s);
        s=String.format("%-6.2f","12.345");//总长度不足,以实际长度为准,结果为12.35
        System.out.print("\n"+s);
    }
    s=String.format("%04d",5);//0(零)表示用0填充。结果为0005
    System.out.print("\n"+s);
    s=String.format("%7s","0中国1");
    System.out.print("\n"+s);
}
import java.time.LocalDate

s=sc.next();//读入的是字符串的日期值
birthday=LocalDate.parse(s);//将字符串方式日期转换成LocalDate型

从文件输入

import java.io.file;

Scanner sc=new Scanner(new File("StudentInfo.txt"));//输入的源头是文件StudentInfo.txt

void append()throws Exception{}
public static void main(String [] x)throws Exception{}

2.4.2 学生数组的两种排序方式

2.5 一些工具类的使用

2.6 综合示例

2.7 本章小结