zoukankan      html  css  js  c++  java
  • Book

    04

    switch(e): {
        case1: case2:
            statement1;
            break;
        default:
            statment2;        
    } 

    05

    自顶向下

    分解: 将大型任务分解成简单的子任务. (分解任务, 不是分解代码) [分解过程中还要注意抽象出公共组件被公共利用

    06 

    随机数种子, java 中的随机数, 需要给定一个初始值, 在这个初始值基础上进行随机, 这个起点, 被称作: 种子.

    由于每次对随机数生成器调用都会更新种子,所以,每次随机出来的数字都是不同的随机数.

     创建随机数类 RandomGenerator, 这个类也是 java.util 中的子类.

    主要的方法:

    static RandomGenerator getInstance() 返回一个 RandomGenerator 类的实例

    int nextInt(int n)    返回从 0 ~ n 的随机数

    int nextInt(int low, int high)    返回从 low ~ high 的随机数

    double nextDouble() 返回 0 ~ 1 的double 双精度类型数

    double nextDouble(double low, double high)

    boolean nextBoolean()

    boolean nextBoolean(double p)  p 是介于 0-1 的小数, 代表是 true 的概率

    Color nextColor()

    void setSeed(long seed)    设置起始种子

    举例:

    import acm.program.*;
    import acm.util.*;
    
    public class Craps extends ConsoleProgram {
        public void run() {
            int total = rollTwoDice();
            if (total == 7 || total == 11) {
                println("That's a natural, you win.");
            } else if (total == 2 || total == 3 || total == 12) {
                println("That's craps. You loose.");
            } else {
                int point = total;
                println("Your point is " + point + ".");
                while (true) {
                    total = rollTwoDice();
                    if (total == point) {
                        println("You made our point, you win. ");
                        break;
                    } else if (total == 7) {
                        println("That's a 7. you lose.");
                        break;
                    }
                }
            }
        }
        
        private int rollTwoDice() {
            int d1 = rgen.nextInt(1, 6);
            int d2 = rgen.nextInt(1, 6);
            int total = d1 + d2;
            println("Rolling dice: " + d1 + " + " + d2 + " = " + total);
            return total;
        }
    /* create an instance variable for the random number generator */
        private RandomGenerator rgen = RandomGenerator.getInstance();
        
    }

    Java 将初始种子默认为内部系统时钟上注册的时间.(时间不能重复). 因此每次运行程序的序列都会改变。

    然而,可以用 setSeed方法随机序列指定具体的起始点。如果再程序开始时这样做, 那么随机值每次都一样.

    public class Rational {
        public Rational() {
            this(0);    // 调用构造函数的意思, 调用的就是 Rational(int n)
        }
        
        public Rational(int n) {
            this.n = n;
        }
        
        private int n;
    }

    this(0)  调用构造函数. this 本身就代表实例, 也就是代表 Rational 实例, this(0) 就是代表调用这个类的构造函数.

    要避免在程序的多个部分编写相同的代码, 复制代码以通常会产生严重的维护问题,因为这很容易让粗心的维护人员改变代码的某个副本而没有同时更新其他副本.

    调用超类构造函数
    • 以明确调用 this 开始的类调用该类的其他构造函数中的某一个(如上例的 this(0)), 将确保调用超类构造函数这一责任委托给该构造函数.
    • 以明确开始调用 super 开始的类调用超类里的构造函数, 该超类匹配提供的参数列表。
    • 不以调用 super 或 this 开始的类调用没有参数的默认超类构造函数。

    规则: 如果类没有定义任何自己的构造函数, Java 会自动定义默认构造函数, 自动生成的默认构造函数主体是空的,因此实际上它不进行任何初始化。 然而,定义这样的构造函数确实可以确保继承层次结构里的每个类都有可以调用的构造函数。但是要注意,如果类定义包括(自定义)构造函数,就不在创建默认构造函数,在这种情况下,所有自雷的构造函数必须明确调用其超类里的某个构造函数。

    07

    包装类: 原始类型封装成类, 进而增加一些类方法,  例如 int -> Integer.

    08

    枚举类, 例如:

    public enum Weekday {

    SUNDAY, MONDAY, TUESDAY, WEDESDAY, THURSDAY, FRIDAY, SATURDAY

    }

    Character 类中比较有用的方法:

    static boolean isDigit(char ch)  是不是数字

    static boolean isLetter(char ch)  是不是字母

    static boolean isLetterOrDigit(char ch)  是不是数字或字母

    static boolean isUpperCase(char ch)  是不是大写字母, isLowerCase(char ch) 是不是小写字母

    static boolean isWhitespace(char ch)  是不是空白

    static char toLowerCase(char ch)  转换成小写字母  toUpperCase(char ch)  转换成大写字母

    String 类 常用方法:

    int length()

    char charAt(int index)

    String concat(String s2)

    String substring(int p1, int p2)  返回从 p1 到 p2 的子串

    String substring(int p1)  返回从 p1 到 尾的字串

    String trim()  去掉收尾空格

    boolean equals(String s2)

    boolean equalsIgnoreCase(String 2)

    int indexOf(char c) 或 int indexOf(String s2)

    int indexOf(char c, int start) 或 int indexOf(String s2, int start)

    boolean startsWith(String prefix)

    boolean endsWith(String suffix)

    string toUpperCase()

    string toLowerCase()

    StringTokenizer: 就是把字符串按照某种分割符分割开, 然后可以依次判断被分割的内容.

    比如 java 的 StringTOkenizer 类, 是 java.util 中的, 有3个构造函数:

    new StringTokenizer(String str)   // 创建一个空白令牌

    new StringTokenizer(String str, String dlims)  // 创建一个带分隔符是 dlims 的令牌

    new StringTokenizer(String str, String delims, boolean returnDelims)  // 如果第三个参数是 true, 返回定界符令牌

    另外, 还有两个有用的方法:

    boolean hasMoreTokens()  // 查看按照分隔符, 是否还有剩余令牌

    String nextToken()  // 返回下一个令牌

    这里有一个举例, 就是随便输入一行字符, 根据判断规则, 把单词重新编码

    /*
     * File: PigLatin.java
     * ----------------------
     * This file takes a line of text and converts each word into Pig Latin.
     * The rules for forming Pig Latin words are as follows:
     * - If the word begins with a vowel, add "way" to the end of the word.
     * - If the word begins with a consonant, extract the set of consonants up
     * to the first vowel, move that set of consonants to the end of the word,
     * and add "ay".
     */
    
    import acm.program.*;
    import java.util.*;
    
    public class PigLatin extends ConsoleProgram {
        public void run() {
            println("This program translates a line into Pig Latin.");
            String line = readLine("Enter a line: ");
            println(translateLine(line));
        }
        
        private String translateLine(String line) {
            String result = "";
            StringTokenizer tokenizer = new StringTokenizer(line, DELIMITERS, true);
            while (tokenizer.hasMoreTokens()) {
                String token = tokenizer.nextToken();
                if (isWord(token)) {
                    token = translateWord(token);
                }
                result += token;
            }
            return result;
        }
        
        private boolean isWord(String token) {
            for (int i = 0; i < token.length(); i++) {
                char ch = token.charAt(i);
                if (!Character.isLetter(ch)) return false;
            }
            return true;
        }
        
        private String translateWord(String word) {
            int vp = findFirstVowel(word);
            if (vp == -1) {
                return word;
            } else if (vp == 0) {
                return word + "way";
            } else {
                String head = word.substring(0, vp);
                String tail = word.substring(vp);
                return tail + head + "ay";
            }
        }
        
        private int findFirstVowel(String word) {
            for (int i =0; i < word.length(); i++) {
                if (isEnglishVowel(word.charAt(i))) return i;
            }
            return -1;
        }
        
        private boolean isEnglishVowel(char ch) {
            switch (Character.toLowerCase(ch)) {
                case 'a': case 'e': case 'i': case 'o': case 'u':
                    return true;
                default:
                    return false;
            }
        }
        
        private static final String DELIMITERS = "!@#$%^&*()_+={[}]:;"'<,>.?/~`|\ ";
    }

    10

     Java 事件模型, 对象的每个事件都是 java.util 程序包中 EventObject 类的子类. 例如下边的类

    • MouseEvent 鼠标事件
    • KeyEvent 键盘按键
    • ActionEvent 表示用户采取用户界面的动作,例如单击屏幕上的按钮

    在Java 事件模型中, 事件对象本身不执行任何动作,实际上,事件被传递给其他某个对象,该对象负责对那种特定类型事件作出响应, 这种对象成为侦听器. 不同类型的侦听器对应不同事件。每个侦听器都定义为接口

    例如: public class MyProgram extends GraphicsProgram implements MouseListener   然后实现 MouseListener 接口请求的每种方法。(所有方法都要实现)

    但是本章中, 这种接口实现是多余的,因为 acm.program 类声明自身为鼠标事件,键盘事件和动作事件的监听器,并为相应接口中所需的每个方法提供默认定义,这样,我们只需要关心我们想要重写的方法就可以,所以我们就不用再 implements 侦听器了.

    java.awt.event.* 里有本章用到的事件.

    import acm.graphics.*;
    import acm.program.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class DrawStarMap extends GraphicsProgram {
        public void init() {
            // 这里调用了父类的 addMouseListeners() 方法
            addMouseListeners();
        }
        
        // 这里的名字是固定的, 必须交 mouseClicked, 实际上这是接口定义好的
        public void mouseClicked(MouseEvent e) {
            GRect rc = new GRect(e.getX(), e.getY(), RECT_SIZE, RECT_SIZE);
            rc.setFilled(true);
            add(rc);
            
        }
        
        private static final double RECT_SIZE = 20;
    }

    对 addMouseListeners 的调用将程序注册为画布内发生的所有鼠标事件的侦听器. 谁被注册为侦听器了, 谁就可以通过调用固定的方法来根据侦听的情况作出反应.

    mouseListener 接口:

    • void mousePressed(MouseEvent e)
    • void mouseReleased(Mouse Event e)
    • void mouseClicked(Mouse Event e)
    • void mouseEntered(Mouse Event e)    鼠标进入画布
    • void mouseExited(Mouse Event e)    鼠标移出画布

    mouseMotionListener 接口:

    • void mouseMoved(MouseEvent e)    释放鼠标按钮的移动
    • void mouseDragged(MouseEvent e)    按住鼠标按钮的移动

    而 addMouseListeners 本身就激活了这两个接口的侦听器

    import acm.graphics.*;
    import acm.program.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class DrawLines extends GraphicsProgram {
        public void init() {
            addMouseListeners();
        }
        
        public void mousePressed(MouseEvent e) {
            line = new GLine(e.getX(), e.getY(),e.getX(), e.getY());
            add(line);
        }
        
        public void mouseDragged(MouseEvent e) {
            line.setEndPoint(e.getX(), e.getY());
        }
        
        private GLine line;
    }

    mousePressed 和 mouseDragged 这两个函数是相辅相成的关系. 都有用

    实际上 mousePressed 只是画了一个点, 从我们的角度看, 这个点没有也无所谓, 只要有拖动函数画线就可以了,但是,因为拖动函数只是将线的重点设置为当前鼠标位置, 所以需要先创建一个线,而创建线本身这个事情,不适合在拖动这个动作中完成,因为拖动这个动作,到底是拖动到什么位置才创建对象呢,所以创建对象的这个事情本身适合在 mousePressed 中做, 而创建line对象本身是需要制定起始和终点坐标的,所以才顺便点了一个点line = new GLine(e.getX(), e.getY(),e.getX(), e.getY());.

    在画布上拖动对象

    我的程序

    import acm.graphics.*;
    import acm.program.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class DragMyObjects extends GraphicsProgram {
        public void init() {
            addMouseListeners();
            gr = new GRect(0,0, RECT_WIDTH, RECT_HEIGHT);
            gr.setFilled(true);
            gr.setFillColor(Color.blue);
            add(gr);
        }
        
        public void mousePressed(MouseEvent e) {
            if ( (e.getX() >= gr.getX() && e.getX() <= (gr.getX() + RECT_WIDTH))
                    && (e.getY() >= gr.getY() && e.getY() <= (gr.getY() + RECT_HEIGHT))) {
                isClicked = true;
            } else {
                isClicked = false;
            }
        }
        
        public void mouseDragged(MouseEvent e) {        
            if (isClicked == true) {
                gr.setLocation(e.getX(), e.getY());
            }
        }
        
        private boolean isClicked = false;
        private GRect gr;
        private final int RECT_WIDTH = 40;
        private final int RECT_HEIGHT = 20;
    }

    书中例子

    import acm.graphics.*;
    import acm.program.*;
    import java.awt.*;
    import java.awt.event.*;
    
    public class DragObjects extends GraphicsProgram {
        public void init() {
            GRect rect = new GRect(100, 100, 150, 100);
            rect.setFilled(true);
            rect.setColor(Color.blue);
            add(rect);
            GOval oval = new GOval(300, 115, 100, 70);
            oval.setFilled(true);
            oval.setFillColor(Color.red);
            add(oval);
            addMouseListeners();
        }
        
        public void mousePressed(MouseEvent e) {
            last = new GPoint(e.getPoint());
            gobj = getElementAt(last);
            if (gobj != null) gobj.sendToFront();
        }
        
        public void mouseDragged(MouseEvent e) {
            if (gobj != null) {
                gobj.move(e.getX() - last.getX(), e.getY() - last.getY());
                last = new GPoint(e.getPoint());
            }
        }
        
        private GObject gobj;
        private GPoint last;
    }

    我的例子, 如果有多个图形, 会比较麻烦, 因为我们有用 getElementAt 函数, 这个应该是画布提供的函数.

    键盘事件

    addKeyListeners 注册键盘侦听器.

    void keyPressed(KeyEvent e)  按下键盘

    void keyReleased(KeyEvent e)    释放键盘

    void keyTyped(KeyEvent e)  按下再释放时调用

    getKeyCode: 知道按哪个键

    getKeyChar: 知道按哪个字母

    KeyEvent e 本身有很多表示按下的是哪个键, 比如: KeyEvent.VK_UP 表示按下上箭头

    举例:

    public void keyPressed(KeyEvent e) {

        if (gobj != null) {

            switch(e.getKeyCode()) {

                case KeyEvent.VK_UP: fobj.move(0, -1); break;

                case KeyEvent.VK_DOWN: fobj.move(0, +1); break;

                case KeyEvent.VK_LEFT: fobj.move(-1, 0); break;

                case KeyEvent.VK_RIGHT: fobj.move(+1, 0); break;

            }

        }

    }

    11, 12, 13

     普通数组 跟 C 类似, 但是也是堆类型

    int[] intArray = new int[10];  // 普通类型数组(非对象类型)

    int[] intArray = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};  // 也可以

    import acm.program.*;
    import acm.util.*;
    
    public class TestArray extends ConsoleProgram {
        public void run() {
            int[] intArray = new int[10];
            for (int i = 0; i < 10; i++) {
                intArray[i] = i;
                println(intArray[i]);
            }
        }
    }

    Student[] studentArray = new Student[5];  //对象数组, 同样也并未初始化

    如果数组名作为参数传递, 那么肯定是传递的引用(地址), 所以函数内部和外部实际上是共用的同一个数组(传地址,而不是传值)

    多维数组: char[][] charArray = new char[3][3];

    多维数组作为参数传递跟单个数组是一样的, 同时, 比如 mulArray[3][3], 如果传递的是 mulArray[0], 表示将数组的第一行全部传递(跟C一样)

    import acm.program.*;
    import acm.util.*;
    
    public class TestArray extends ConsoleProgram {
        public void run() {
            int[][] mulArray = {
                {0,0,0},
                {1,1,1},
                {2,2,2}
            };
            testSingle(mulArray[0]);
            println(mulArray.length);
            println(mulArray[0].length);
            println("-----------------");
            for (int i = 0; i < mulArray.length; i++) {
                for (int j = 0; j < mulArray[0].length; j++) {
                    println(mulArray[i][j]);
                }
            }
        }
        
        private void testSingle(int[] temp) {
            for (int i = 0; i < temp.length; i++) {
                temp[i] = 10;
            }
        }
        
    }

    Array 与 图像处理

     在Java中, 图像是矩阵(2维)数组,每一行是一系列单个像素值. 数组中的每个元素的值表示出现在屏幕上对应像素位置的颜色.

    像素: 可以理解为将图像的小块, 每个图片都是由这种小块组成,而小块自己本身是有颜色的,这个颜色就存储在这个数组元素里.

    而颜色本身, 可以拆分为4个维度,

    维度1: (可能是类似透明度啥的), 0~255, 占 8 个字节: 不重要.

    下边三个维度, 就是我们经常说的 RGB (red, green, blue), 根据这三种颜色的比例,可以组合出不同的颜色.

    维度2: 红: 0~255, 占8个字节:

    维度3: 绿: 0~255, 占8个字节:

    维度4: 蓝: 0~255, 占8个字节;

     所以, 实际上这个32位的2进制数, 就可以唯一决定一个像素的颜色。

    所以, 实际上一个 int 型的二维数组就可以用来存储一个图片.

    int[][] pixelArray = image.getPixelArray(); 图像的高度就是行数, 图像的宽度就是每一行的像素数.

    int height = pixelArray.length; (2维数组的length 就是"高度", 即多少行)

    int width = pixelArray[0].length; (像素数)

    图像翻转

    import acm.graphics.*;
    import acm.program.*;
    
    public class ImageVertical extends GraphicsProgram {
        public void run() {
            // 此方法, 图片必须在源文件目录下
            GImage myImage = new GImage("aa.jpg", 0, 0);
            GImage wwImage = flipVertical(myImage);
            add(wwImage);
        }
        
        /* 
         * 图像翻转 
         * 通过传参可以看出, image 本身应该是类似传值, 不可改变.
         * */ 
        private GImage flipVertical(GImage image) {
            int[][] array = image.getPixelArray();
            int height = array.length;
            for (int p1 = 0; p1 < height/2; p1++) {
                int p2 = height - p1 - 1;
                int[] temp = array[p1];
                array[p1] = array[p2];
                array[p2] = temp;
            }
            // 2维图像数组, 可以构建一个图片
            return new GImage(array);
        }
    }

     灰度图像

    import acm.graphics.*;
    import acm.program.*;
    
    public class GrayImage extends GraphicsProgram {
        public void run() {
            // 此方法, 图片必须在源文件目录下
            GImage myImage = new GImage("aa.jpg", 0, 0);
            GImage wwImage = grayPicture(myImage);
            add(wwImage, 0, 0);
        }
        
        private GImage grayPicture(GImage image) {
            int[][] array = image.getPixelArray();
            int height = array.length;
            int width = array[0].length;
            
            for (int i = 0; i < height; i++) {
                for (int j = 0; j < width; j++) {
                    int pixel = array[i][j];
                    int r = GImage.getRed(pixel);
                    int g = GImage.getGreen(pixel);
                    int b = GImage.getBlue(pixel);
                    
                    int xx = computeLuminosity(r, g, b);
                    array[i][j] = GImage.createRGBPixel(xx, xx, xx);
                    
                }
            }
            return new GImage(array);
        }
        // 图片的亮度的比例,大概0.3 0.6 0.1  这个值是电视台给的固定值
        private int computeLuminosity(int r, int g, int b) {
            return GMath.round(0.299*r + 0.587*g + 0.114*b);
        }
    }
    位操作与颜色分解

    左移动: value << number of bits,  x << 1,  向左移动1位, 右边补0

    右移动: 更加复杂一点, 用到再说吧

    分解像素组件

    分解蓝色: 只需要 (与操作)& 0XFF, (前24位都位0,最后8位全为1), 这样无论是什么颜色的数据, 最后的结果只有后8位(代表蓝色的)有实际值, 其他为0.

    分解红色,绿色 需要先移位,然后再类似与操作这种, 实际上函数已经帮我们封装好了这些操作系统,我们可以直接调用, img.getBule(int) 类似这种.(如上栗灰度图片)

    ArrayList

    属于 java.util 包, 通用类

    动态数组, ArrayList 定义时指定类型,而且这个类型必须是 object, 不能是原始类型。

    常用方法:

    boolean add(<T> element)   这里的 T 没有指定具体类型, 而 ArrayList 是什么类型, 这个 T 就是什么类型. (所以,在 ArrayList 里存储的对象,也都是相同类型)

    void add(int index, <T>element)

    <T> remove(int index)

    void clear()   清空列表

    int size()

    <T> get(int index)

    <T> set(int index, <T>value)  改变指定位置的值为新值

    int indexOf(<T> value)

    boolean isEmpty()

    ArrayList<String> stringList = new ArrayList<String>();

    ArrayList<int> intList = new ArrayList<int>();   // 这是错误的,要用包装类

    ArrayList<Integer> intList = new ArrayList<Integer>();

    Iterator<String> iterator = intList.iterator();

    while (iterator.hasNext()) {

        println(iterator.next());

    }

    文件操作

    Java.io 包

    FileReader rd = new FileReader("abc.txt");

    BufferedReader  可以方便逐行读取文件

    文件 IO 读取要加异常处理.

    Scanner 类, java.util 包, 更加方便的实现逐行读取, Scanner 类有70多个方法,甚至可以实现 nextInt() 方法,看令牌流下一个是否是int型,不是可以抛异常.

    HashMap ,key,value 形式

    Map<String, String> stateMap = new HashMap<String, String>();

  • 相关阅读:
    Python的with语句(文件打开方式)
    python代码异常范围检查方法(非常实用)
    python一标准异常总结大全(非常全)
    python里pickle模块
    pyhon文件操作典型代码实现(非常经典!)
    codeblocks中cocos2dx项目添加新的.cpp和.h文件后编译运行的方法
    ubuntu安装cocos2dx
    学习资料整理
    Spring学习笔记--在SpEL中筛选集合
    Spring学习笔记--Spring表达式语言SpEL
  • 原文地址:https://www.cnblogs.com/moveofgod/p/12286823.html
Copyright © 2011-2022 走看看