软件方法

5 minute read

目录

软件方法

课程要求

学习面向对象这种软件开发方法(目前概念越来越广),通过java来了解面向对象的编程具体怎么实现。

随记

  1. 类,对象:
    • 对象是类的一个实例
    • c语言可以构建面向对象所有的结构
    • 类集合了属性和方法
  2. 面向对象的三大特征:
    • 封装(encapsulation):
      • private, protected, public
      • 可作用于属性和方法,一般构造方法和成员方法都是public, 属性都是private
      • 一般是隐藏对象的属性和实现细节,但是提供方法的接口
      • 提供公开的方法
      • 提高了软件开发的效率
    • 继承(inheritance):
      • 子类与父类
      • 子类自动具有父类属性和方法,添加自己特有的属性和方法,并且子类使用父类的方法也可以覆盖/重写父类方法
      • 可以实现代码的复用(当然功能不止于此)
    • 多态(polymorphism):
      • 父类有多个子类
      • 子类覆盖/重写父类方法
      • 相当于是根据实际创建的对象类型动态决定使用哪个方法
      • 所有的子类都可以看成父类的类型,运行时,系统会自动调用各种子类的方法
      • UML可以画出类之间的关系
  3. java程序设计
    • 百分百面向对象
      • 不存在类以外代码
      • 只能采用面向对象方法编程
      • java文件命名规范
        • 必须以.java结尾
        • 源文件中如果只有一个类,文件类必须与该类名相同
        • 如果有多个类,且没有public类,文件名可与任一类名相同
        • 有多个类,且有public类,文件名必须与该类名相同
        • 一个JAVA源文件只能有一个public类,一个文件中只能有一个main主函数
    • 静态方法/static,可以直接用类和函数名直接调用,和普通方法的区别是不用new一个示例
      • static 方法可以直接调用,abstract方法存在的类肯定是抽象类
      • 抽象方法不定义具体内容
    • 多态的实现,先定义抽象的(abstract)父类,然后子类继承父类然后定义父类的抽象方法
      • 通过抽象方法固定通用接口
      • 子类通过强制实现抽象方法实现多态
      • 抽象父类可以定义属性和构造函数
      • 抽象父类不能实例化,只能通过向上转型的方法定义
      • 抽象父类可以向下转型成子类
      • 父类的方法一般是抽象方法,不定义具体内容,留给子类定义,父类出现的抽象方法子类必须全部定义
      • 多态的主要特点就是父类的方法全部是抽象的
  4. 多态例子
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("看家");  
    }  
}

PPT整理

1. 对象,类

  • 使用对象之前要先声明和创建
  • 类定义了对象的类型,所有对象都是类的实例,所有的类描述了属性和定义了方法

2.面向对象

  • 面向对象的编程有4个特点
  • 封装:保护类的属性和方法, 类里面的属性的数据是private的, public的方法定义了对象的接口。权限修饰符: private, default, protected, public。
  • 继承:B继承A,重用,修改,添加,A所有的属性都存在于B中,A的方法可以在B中重新定义,B方法的改动不会影响A
  • 多态:一个对象属于多个类,通过使用不同类中的方法属于不同的类,父类是抽象类,各个子类继承父类并定义方法,调用的时候根据不同子类调用方法。判断类型是否相同instanceof,声明的时候可以这么声明: A a = new B(),其中B是A的子类, 这种声明方法叫做向上转型。向下转型: B b = (B) a
  • 动态链接: 通过PPT上的例子,我感觉和继承很像,这部分需要更深入了解才能明白。

3.JAVA

  • main的格式:
  • 数据类型: int, float, double, char, string, boolean, byte, long, short, JAVA里面也有这些数据类型的类:

其中Characte应该为Character

  • JAVA关键字this, super

  • x = bool ? a : b,表示如果bool为true,执行a,如果为false执行b

  • for(Point p : this.getVect())表示遍历

  • exception 异常:

还有异常的抛出throws

try-catch-finally

try 
{  
	    // 可能会发生异常的程序代码  
} 
catch (Type1 id1)
{  
	    // 捕获并处置try抛出的异常类型Type1  
} 
catch (Type2 id2)
{  
	    //捕获并处置try抛出的异常类型Type2  
}
finally 
{  
	    // 无论是否发生异常,都将执行的语句块  
}

自定义异常:

class NombreNegatifException extends Exception
{
    public NombreNegatifException()
    {
    System.out.println("Vous avez un nombre négatif !");
    } 
}

在类的方法中抛出新的异常:

public int Count() throws Exception{
    if (...){
        throw new Exception("...");
    }
}
  • 文件读写:

类FileReader,FileWriter,使用里面的方法read()和write(x)和close()

比如:

  • 枚举类型enum,举例说明
public enum Jour 
{
    LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI, DIMANCHE;
}

class EssaiJour 
{
    public static void main(String[] args) 
    {
        Jour jour = Jour.valueOf(args[0]);
        if (jour == Jour.SAMEDI) System.out.print("fin de semaine : ");
        switch(jour) 
        {
            case SAMEDI :
            case DIMANCHE :
            System.out.println("se reposer");
            break;
            default :
            System.out.println("travailler");
            break;
        }
    }
}
  • 接口interface, 迭代器iterator

举例:

class Main 
{
    @FunctionalInterface
    public interface maFonction 
    {
        Integer appliquer(Integer p);
    }

    public static Vector<Integer> transforme(Vector<Integer> v, maFonction function) 
    {
        Vector<Integer> nouveauVect = new Vector<Integer>();
        for (int i = 0; i < 3; i++) 
        {
        nouveauVect.add(function.appliquer(v.get(i)));
        }
        nouveauVect.add(v.get(3));
        return nouveauVect;
    }

    public static void main(String[] args) 
    {
        Vector<Integer> vi = new Vector<Integer>(4);
        vi.add(1); vi.add(4); vi.add(83); vi.add(18);
        System.out.println("Les valeurs du vecteur initial : ");
        System.out.print(vi.get(0)+" "); System.out.print(vi.get(1)+" "); 
        System.out.print(vi.get(2)+" "); System.out.println(vi.get(3));
        vi = transforme(vi,s -> (s * 2));
        System.out.println("Les valeurs du vecteur modifié : ");
        Iterator iter = vi.iterator();
        while (iter.hasNext())
        {
            System.out.print(iter.next() + "");
        }
        System.out.println();
    }
}

4.数据结构

  • 数据结构一般含有以下功能:创建,插入,寻找,删除,排序
  • 二维数组,举例说明:
String tab[][]={ {"a", "e", "i", "o", "u"}, {"1", "2", "3", "4"} };
int i = 0, j = 0;
for(String sousTab[] : tab) 
{
    j = 0;
    for(String str : sousTab) 
    { 
        System.out.println("Valeur du tableau à l'indice ["+i+"]["+j+"]: " + tab[i][j]);
        j++;
    }
    i++;
}

声明数组:数组类型加变量名

或者

int tabEntiers[];
tabEntiers = new int[40]; 
// création effective du tableau précédent
  • 列表,包含ArrayList, LinkedList

ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。对于随机访问get和set,ArrayList优于LinkedList,因为ArrayList可以随机定位,而LinkedList要移动指针一步一步的移动到节点处。(参考数组与链表来思考)。对于新增和删除操作add和remove,LinedList比较占优势,只需要对指针进行修改即可,而ArrayList要移动数据来填补被删除的对象的空间。

public class Liste<T> 
{
    protected T valeur; 
    protected Liste<T> succ;
    protected Liste<T> pred;
    
    public T valeur()
    { 
        return valeur;
    }

    public void changerValeur(T x)
    { 
        valeur = x; 
    }

    public Liste<T> succ()
    { 
        return succ; 
    }
    
    public void changerSucc(Liste<T> y)
    { 
        succ = y; 
    }

    public void changerPred(Liste<T> y)
    { 
        pred = y; 
    }
} 

这是一个链表的简写,每一层包含了上一个元素,这一个元素,下一个元素

  • 哈希表,通过建立KV关系查找,相比于之前的顺序访问或者其他指数访问要快。
import java.util.HashMap;
public class TestHash 
{
    public static void main(String[] args) 
    {
        HashMap<String,String> annuaire = new HashMap<String,String>();
        // ajout des valeurs
        annuaire.put("Alfred","2399020806");
        annuaire.put("Daniel", "2186000000");
        // obtention d'un numéro
        if (annuaire.containsKey("Danielle")) 
        {
            String num = annuaire.get("Danielle");
            System.out.println(Danielle : "+num");
        }
        else 
        {
            System.out.println("pas trouve");
        }
    }
}
  • 树状结构tree

一般包含结点,结点的度(该结点下有多少子树的数目),树的度

不同的遍历方法:

前序遍历,首先结点,然后左子树,右子树
中序遍历,左子树,结点,右子树
后序遍历,左子树,右子树,结点
层序遍历,从上到下,从左到右

class Arbre 
{
    protected <T> valeur;
    protected Arbre filsGauche, filsDroit; 
    public <T> valeur() 
    { 
        return valeur; 
    }
    public boolean existeFilsGauche() { return filsGauche != null; } 
    public boolean existeFilsDroit() { return filsDroit != null; }
    public Arbre filsGauche() { return filsGauche; }
    public Arbre filsDroit() { return filsDroit; }
    public void affecterValeur(<T> c) { valeur = c; }
    public void affecterFilsGauche(Arbre g) { filsGauche = g; }
    public void affecterFilsDroit(Arbre d) { filsDroit = d;}
    public boolean feuille() {return (filsDroit==null && 
    filsGauche==null); 
}

public int hauteur() 
{
    int g = existeFilsGauche() ? filsGauche.hauteur() : 0;
    int d = existeFilsDroit() ? filsDroit.hauteur() : 0;
    return Math.max(g,d) + 1 ;
}
// Constructeurs
public Arbre(T val) 
{
    valeur = val;
    filsGauche = filsDroit = null;
}
public Arbre(T val, Arbre<T> g, Arbre<T> d) 
{
    valeur = val;
    filsGauche = g; filsDroit = d;
}

// Affichage
public void afficherPrefixe() 
{
    System.out.print(valeur+"\t");
    if (existeFilsGauche()) filsGauche.afficherPrefixe();
    if (existeFilsDroit()) filsDroit.afficherPrefixe();
}

public void afficherInfixe() 
{
    if (existeFilsGauche()) filsGauche.afficherInfixe();
    System.out.print(valeur+"\t");
    if (existeFilsDroit())filsDroit.afficherInfixe();
}

public void afficherPostfixe() 
{
    if (existeFilsGauche()) filsGauche.afficherPostfixe();
    if (existeFilsDroit())filsDroit.afficherPostfixe();
    System.out.print(valeur+"\t");
}

二叉排序树是指左子树小于结点小于右子树,而且结点值不重复。判断是否为二叉排序树:

public boolean superieur(char x) 
{
// vrai si x est supérieur à tous les éléments de l’arbre
    if (feuille()) return (x>=valeur);
    else return 
    (((this.existeFilsGauche())? (this.filsGauche).superieur(x):true) & 
     ((this.existeFilsDroit())? (this.filsDroit).superieur(x):true));
} 
public boolean inferieur(char x) {//similaire a superieur ... }
public boolean binrech() {
    if (feuille()) return true;
    else return
    ((existeFilsGauche()?(filsGauche.superieur(valeur) && filsGauche.binrech()):true) & 
     (existeFilsDroit()?(filsDroit.inferieur(valeur) && filsDroit.binrech()):true));
} 

5. 常用数据结构方法

二维数组array[][]的定义和访问

数据结构 vector<String> ArrayList<String> LinkedList<String> HashMap<String,int>
添加 add(i, str) add(i,str) add(i,str) put(str,i)
查找 get(i) get(i) get(i) get(str)
索引 indexOf(str) indexOf(str) indexOf(str)  
删除 remove(i)/remove(str) remove(i/str) remove(i/str) remove(i)
清除 clear() clear() clear()  
查看大小 size() size() size() size()
迭代器 iterator() iterator() iterator()  
变成数组   toArray() toArray()  

hashmap还可以返回键值对entryset(),也可以判断是否含有key和value,containsKey(),containsValue()

Hashmap创建的时候需要继承

TP整理

  1. 定义构造函数时也需要声明权限修饰符,构造函数不需要返回值,调用的时候直接在声明一个对象的时候调用
  2. 访问成员变量的时候用.
  3. 方法中除了构造函数都需要权限修饰符和返回类型名
  4. 在类中调用成员变量可以直接调用
  5. 字符串之间用+连接
  6. 当一个类中有main函数时,一般这么定义: public static void main(String[] a){}
  7. 在定义类的时候不要有()
  8. 向量的创建和声明: Vector<T> mesObjectsG = new Vector<T>();
  9. 打印的使用: System.out.println()
  10. 成员函数在类的开头只是声明,并没有创建,所以在方法中创建
  11. for循环的使用: for(Point p : seg.getVecP())
  12. Vector.add(), 向量的添加
  13. Vector.get(i), i从0开始, 向量的访问
  14. Vector.size()返回int值,是vector的大小
  15. TP1中为了让图形可视化,每个类都需要extends ObjectGraphique
  16. 什么时候需要在类定义方法时new一个对象: 当这个对象来自其他类同时改变这个对象会对新创建的类产生影响,所以一般还是new一个对象比较好
  17. 基本的数据类型: int, string, float, boolean不需要new, 声明的时候也不需要构造函数
  18. 继承的时候可以用super()来调用继承类的构造函数
  19. 异常的抛出: 在定义类中的方法的时候,需要抛出的方法需要在创建时添加一句throws Exception, 调用的时候使用throw new Exception(“…”)
  20. 也可以throws IOException这样已经定义好的抛出类型
  21. 文件读入: Reader reader = new FileReader(textname.txt)
  22. 逐行读入: BufferedReader in = new BufferedReader(reader); String line = in.readline()
  23. 分词器: StringTokenizer st = new StringTokenlizer(line, DeleteChar); 然后就可以像迭代器一样调用, if(st.hasMoreTokens()){st.nextToken()}
  24. 文件写入: Writer writer = new FileWriter(newtextname); writer.write(“…”)
  25. 将链表中所有的单词写入一个文件: for (object k : this){writer.write(k+”\n”);writer.flush()} 写入完毕后, writer.close()
  26. 哈希表判断key是否在哈希表中: HashMap.containsKey(…), 返回值为布尔类型
  27. 哈希表中添加元素: HashMap.put(key, value)
  28. 哈希表可以返回键值对,键对和值对,调用HashMap.entrySet()、HashMap.keySet()、HashMap.valueSet()
  29. 通过键来访问哈希表中的值: HashMap.get(key)
  30. EntrySet同样可以通过getKey()和getValue()来访问键值
  31. 在创建一个新类时,对于类的名字可以这么取: Arbre<T>, 这样就表示Arbre类中的数据类型是T
  32. java中的空是null,小写
  33. 记住二叉树高度是怎么写的
  34. 记住二叉树前序中序后序遍历是如何写的
  35. 在进行没有变量x时怎么计算数的结果: 先用迭代访问出左值和右值,然后根据根结点的符号决定进行什么运算
  36. Integer.parseInt(String a)的作用是将整数的String表示转化为Integer
  37. 对于含变量x的二叉树如何在输入x的值的情况下算出结果: 首先遍历左子树,如果左子树的左边有x,那么将输入的值赋给这个结点的x,然后迭代回来计算左结点的值,具体的可以看网站截图
  38. java中final关键字是保证了变量无法修改,只能访问
  39. 字符串的比较用.equals()
  40. Vector.contains(…)可以判断一个值是否在这个向量里
  41. String.charAt(i), 可以将字符串第i个字符赋给char
  42. instanceOf用来判断一个对象是不是一个类的实例: if (a instanceOf A)
  43. 多态的一种应用是: 抽象父类,子类继承抽象父类
Quehry

Quehry

Student

Comments

  Write a comment ...