《Java核心技术(卷I)》学习笔记 (一)

Java核心技术(卷I)学习笔记

第三章 Java基本程序设计结构

[2019-02-27]

  1. 在Java中使用"final"指示常量,一般来说变量名使用全大写字母,且该变量只可以赋值一次。在main方法外使用"static final"定义类常量,可以在同一个类中所有的方法中使用,若定义为"public"则可以再其它类中使用。

  2. Integer是整数类,已封装,而int是基本的数据类型。

  3. public static strictfp void main.........该方法中所有计算使用严格的浮点计算,中间结果不会截断。

  4. 常用数学函数:

    Math.sin Math.cos Math.tan Math.atan Math.atan2 Math.exp Math.log Math.log10 Math.PI Math.E

    1551248540993
  5. 32位的int型数字如果移位运算需要mod32,1<<37 <=> 1<<5。

  6. Java中可使用"+"连接两个字符串,当某个字符串与非字符串类型P连接时,会自动将P转化成字符串类型。

  7. Java中不可直接修改字符串某个位置具体的字符,但是可以修改整个字符串变量,例如,str = str.substring(0,3) + "p!",可将原来的str(内容是Hel)改为"Help!"。

    String类对象被称为不可变对象。

    检测两个字符串(变量)是否相等可使用s.equals(p)。

    (P50)具体参见Java String类 API文档

  8. 有时要检查一个字符串既不是null 也不为空串,这种情况下就需要使用以下条件: if (str != null && str.length() != 0)

  9. 码点与代码单元部分暂时略过

  10. 使用字符串构建器(StringBuilder类)来构建多个短小字符(串)的拼接字符串,最后使用builder.toString方法来得到一个完整的字符串。

  11. (卷I)【P58】 printf 格式化输出控制字符,【P60】时间输出格式,文件读写等。

  12. 在C++ 中, 可以在嵌套的块中重定义一个变量。在内层定义的变量会覆盖在 外层定义的变量。这样, 有可能会导致程序设计错误, 因此在Java 中不允许这样做。

  13. Java中的switch-case结构与C语言中相同:

    switch (choice)
    {
    case 1:
    	break;
    case 2:
    	break;
    case 3:
    	break;
    case 4:
    	break;
    default:
    // bad input
    	break;
    }
  14. 【P76-78】Java大数计算 BigInteger(整数)和BigDecimal(浮点数)

    public class Test {
        public static void main(String[] args) {
            //计算1000!
            BigInteger ans = BigInteger.valueOf(1);
            for(int i=1;i<=1000;i++){
                BigInteger input = BigInteger.valueOf(i);
                ans = ans.multiply(input);
            }
            System.out.print(ans);
        }
    }
  15. Java中数组声明方式有二:Type[] a或者Type a[],一般使用前者,只有Type[] a = new Type[N],才算声明了一个长度为N的数组。多维数组的声明相同,并且可以声明不规则长度的数组,先初始化行数,在分配每一行的长度大小。【P89】

    int[] small Primes = { 2, 3, 5, 7, 11, 13 };//不使用new来初始化

    small Primes = new int[] { 17, 19, 23, 29, 31, 37 };//重新初始化

    --匿名数组???

    copyOf(array,arraylength)数组拷贝。

  16. for each循环,功能与C++、Python相同。

  17. 命令行参数 "String[] agrs",网上有详细说明。

[2019-02-28]--还未UP

第四章 对象与类

  1. OOP三特性:对象的行为、状态和标识。

  2. 类之间三大关系:

    依赖(uses-a)--如果一个类的方法操纵另一个 类的对象,我们就说一个类依赖于另一个类

    聚合(has-a)--聚合关系意味着类A 的对象包含类B 的对象

    集成(is-a)--用于表示特殊与一般关系。

  3. UML ( Unified Modeling Language , 统一建模语言)绘制类图(软工未选修)。

    1551352375509
  4. LocalDate类(感觉好奇怪)

    只访问对象而不修改对象的方法有时称为访问器方法(accesser method)

    会对对象造成影响,改变其状态的方法叫做更改器方法(mutator method)

    import java.time.*;
    /**
     * Orion233
     * print this month‘s calendar
     */
    public class Test {
        public static void main(String[] args) {
            LocalDate date = LocalDate.now();
            int month = date.getMonthValue();
            int today = date.getDayOfMonth() ;
            date = date.minusDays(today - 1); // Set to start of month
            DayOfWeek weekday = date.getDayOfWeek() ;
            int value = weekday.getValue();
    
            System.out.println("Mon Tue Wed Thu Fri Sat Sun" + value) ;
            for (int i = 1; i < value; i++)
                System.out.print("    ");
            while (date.getMonthValue() == month)
            {
                System.out.printf("%3d", date.getDayOfMonth()) ;
                if (date.getDayOfMonth() == today)
                    System.out.print("*");
                else
                    System.out.print(" ") ;
                date = date.plusDays(1) ;
                if (date.getDayOfWeek() .getValue() == 1) System.out.println();
            }
            if (date.getDayOfWeek() .getValue() != 1) System.out.println() ;
        }
    }
  5. Java构造器(所有的Java 对象都是在堆中构造的):

    •构造器与类同名 •每个类可以有一个以上的构造器 •构造器可以有0 个、1 个或多个参数 •构造器没有返回值 •构造器总是伴随着new 操作一起调用

  6. 隐式参数与显式参数

    this标识隐式参数,这样可以更好地实例域与局部变量明显地区分开来。

    成员变量:

    ​ ①成员变量定义在类中,在整个类中都可以被访问。

    ​ ②成员变量随着对象的建立而建立,随着对象的消失而消失,存在于对象所在的堆内存中。

    ​ ③成员变量有默认初始化值。

    局部变量:

    ​ ①局部变量只定义在局部范围内,如:函数内,语句内等,只在所属的区域有效。

    ​ ②局部变量存在于栈内存中,作用的范围结束,变量空间会自动释放。

    ​ ③局部变量没有默认初始化值

    进行局部运算的时候,局部变量会屏蔽全局变量。
    Example:
    Class A
    {
    	int a = 1public static void main(String[] args)
    	{
    		A c = new A();
     		a = 2;
    		System.out.println(a);
    		System.out.println(c.a);
    	}
    }
    public class Person {
        private int age=1000;//定义成员变量,年龄为1000
        public void setAge(int age) {
            age=age;
            System.out.println("方法内的年龄"+age);
        }
        public void sayHello() {
            System.out.println("我的年龄是"+age+".");
        }
    }
    ......
    Person p=new Person();
    p.setAge(20);
    p.sayHello();
    ......
    Results:
    //方法内的年龄20
    //我的年龄是1000.
    
    /*
    如果不同名,那么方法内的变量名代表成员变量;如果同名,那么方法内的变量名就只表示局部变量了,和成员变量一毛钱关系都没有了。
    所以,首先当我们创建了一个Person对象p,在创建对象的时候就已经完成了成员变量的初始化了。成员变量age的初始值是1000。
    当我们p.setAge(20)的时候,其实这个20只在setAge这个方法内起作用,所以输出了方法内年龄20,执行完这句话后,20就被销毁了。
    然后执行sayHello,它里面的age代表的是成员变量的值,所以依旧是1000。
    
    所以这里应该使用this表示当前对象。
    this.age在这里具体表示p对象的age(即p对象的成员变量age)的值是20。
    */
  7. 方法可以访问所属类的私有特性( feature ), 而不仅限于访问隐式参数的私有特性。一个方法可以访问所属类的所有 对象的私有数据。

  8. 另参考:

  9. 可以将实例域定义为final。构建对象时必须初始化这样的域。也就是说, 必须确保在每一个构造器执行之后, 这个域的值被设置, 并且在后面的操作中, 不能够再对它进行修改。例如, 可以将Employee 类中的name 域声明为final , 因为在对象构建之后, 这个值不会再被修改, 即没有setName 方法。

    PS:StringBUilder的例子不大一样,他可以修改,见【P112】

    [2019-03-01]

  10. 如果将域定义为static, 每个类中只有一个这样的域。而每一个对象对于所有的实例域 却都有自己的一份拷贝。

    参考资料:Java中的static关键字解析

    静态变量、静态常量

    静态成员变量虽然独立于对象,但是不代表不可以通过对象去访问,所有的静态方法和静态变量都可以通过对象访问(只要访问权限足够)。

    --What is a field in java?

    --A field is an attribute. A field may be a class’s variable, an object’s variable, an object’s method’s variable, or a parameter of a function.

    field,域是一种属性,可以是一个类变量,一个对象变量,一个对象方法变量或者是一个函数的参数。(补充,class's variables,类的实例变量和静态变量称为class's variables,类属变量,也称类变量或数据域,其实翻译成属性也可以,类属性,听起来不会怪怪的,来自百度百科)。

  11. 可以使用对象调用静态方法e.g.可以用 harry.getNextId( ) 代替 Employee.getNextId( ),但是建议使用类名,而不是对象来调用 静态方法。

    在下面2种情?下使用静态方法:

    <1> 一个方法不需要访问对象状态,其所需参数都是通过显式参数提供(例如:Math.pow )

    <2> 一个方法只需要访问类的静态域(例如:Employee.getNextld)

  12. P132 4.4.4 工厂方法

    1. 博客出处:http://blog.csdn.net/cgwshxs/archive/2008/12/05/3455136.aspx

      静态工厂方法讲解<一> ​ 创建类的实例的最常见的方式是用new语句调用类的构造方法。在这种情况下,程序可以创建类的任意多个实例,每执行一条new语句,都会导致Java虚拟机的堆区中产生一个新的对象。假如类需要进一步封装创建自身实例的细节,并且控制自身实例的数目,那么可以提供静态工厂方法。 例如Class实例是Java虚拟机在加载一个类时自动创建的,程序无法用new语句创建java.lang.Class类的实例,因为Class类没有提供public类型的构造方法。为了使程序能获得代表某个类的Class实例,在Class类中提供了静态工厂方法

      forName(String name),它的使用方式如下:
      
      Class c=Class.forName("Sample"); //返回代表Sample类的实例

      静态工厂方法与用new语句调用的构造方法相比,有以下区别。

      (1)构造方法的名字必须与类名相同。这一特性的优点是符合Java语言的规范,缺点是类的所有重载的构造方法的名字都相同,不能从名字上区分每个重载方法,容易引起混淆。静态工厂方法的方法名可以是任意的,这一特性的优点是可以提高程序代码的可读性,在方法名中能体现与实例有关的信息。例如Gender类有两个静态工厂方法:getFemale()和getMale()。

      Gender.java
      public class Gender{
         private String description;
         private static final Gender female=new Gender("女");
         private static final Gender male=new Gender("男");
         private Gender(String description){this.description=description;}
         public static Gender getFemale(){
           return female;
         }
         public static Gender getMale(){
            return male;
         }
         public String getDescription(){return description;}
      }

      这一特性的缺点是与其他的静态方法没有明显的区别,使用户难以识别类中到底哪些静态方法专门负责返回类的实例。为了减少这一缺点带来的负面影响,可以在为静态工厂方法命名时尽量遵守约定俗成的规范,当然这不是必需的。目前比较流行的规范是把静态工厂方法命名为valueOf或者getInstance。

      valueOf:该方法返回的实例与它的参数具有同样的值,例如:
             
      Integer a=Integer.valueOf(100); //返回取值为100的Integer对象

      从上面代码可以看出,valueOf()方法能执行类型转换操作,在本例中,把int类型的基本数据转换为Integer对象。

      getInstance:返回的实例与参数匹配,例如:

      //返回符合中国标准的日历

      Calendar cal=Calendar.getInstance(Locale.CHINA);

      (2)每次执行new语句时,都会创建一个新的对象。而静态工厂方法每次被调用的时候,是否会创建一个新的对象完全取决于方法的实现。

      (3)new语句只能创建当前类的实例,而静态工厂方法可以返回当前类的子类的实例,这一特性可以在创建松耦合的系统接口时发挥作用。

      静态工厂方法最主要的特点是:每次被调用的时候,不一定要创建一个新的对象。利用这一特点,静态工厂方法可用来创建以下类的实例。 单例类:只有惟一的实例的类。 枚举类:实例的数量有限的类。 具有实例缓存的类:能把已经创建的实例暂且存放在缓存中的类。 具有实例缓存的不可变类:不可变类的实例一旦创建,其属性值就不会被改变。

      静态工厂方法讲解<二> 实例化对象的方法:

      1.构造函数。

      2.静态工厂方法。(我不常用,但JAVA平台库有好多例子)

      对于构造函数,是新建对象是自动调用的方法,返回该对象,主要用于初始化类的成员字段。而另外一种构建对象的方式是采用静态工厂方法。静态工厂方法与别的静态方法没有什么区别,只不过该方法产生的类对象,不做其他事情,如我们常用的Sington单态模式。使用静态工厂方法主要有以下优点:

      第一:静态工厂方法可以突破构造函数不能自由命名的限制,对于不同的工厂方法可以采用不同的会意的名字,是程序具有更好的可读性。JAVA平台库的java.text.Format的子类NumberFormat就有getInstance() , getPrecentInstance() , getCurrencyInstatnce()等静态方法,通过不同的名字产生特定的对象。

      第二:静态工厂方法是用来产生对象用的,至于产生什么类型的对象没有限制,这就意味这只要返回原返回类型或原返回类型的子类型都可以,这样就加大了程序设计和使用的灵活行,如java.util集合框架就采用了这种优势,这样就可以更好达到封装的目的,降低API的数目和用户的使用难度,java.util.Connections是集合框架的辅助类用于对原有的集合类进行进一步封装,产生一些同步的集合,不可修改的视图。都是采用静态工厂方法实现的,至于方法内部的实现类就完全别封装了。也迫使我们使用接口编程。

      第三:静态工厂方法所创建的对象可以在编译时不存在,动态创建对象,采用放射,类似SPRING的IOC容器方转。最典型的例子就是spi服务提供者框架,Service Provider Iframe 是一种用于在运行时刻产生对象的框架,达到对象的创建与使用分离,是对象的客户和对象之间解耦,增加程序的灵活性和可扩展性。既然spi可以动态创建对象,那么采用什么机制来创建什么对象,创建对象的依据是什么了,spi必须一种统一的注册机制,对于要创建的对象,应该在XML文件中配置,到时候,只要提供一个字符串,就可以凭借该字符串来创建配置的对象。简单实现如下:

       class SPITest{
       private static Map SPIMap = new HashMap();
       private void initSPIMapIfNeccury(){
       if(SPIMap == null){
       SPIMap = new HashMap();
       } 
      
      //initMap user the sepecify XML 
      //the map key is a beanName ,the value is a Object which config by XML
      
       }
      
       public Object getInstace(String beanName){
       Object result = null;
       try{
       if(SPIMap.containsKey(beanName)){
       result = SPIMap.get(beanName);
       } else{
       throw new Exception(" please config the xml file ,this bean is not exists!");
       }
       }catch(Exception exce){
       exce.printStackTrace();
       }
       return result;
       }
      }

      可以明显看出待创建的对象具体创建哪个对象,在编译时并不知道,只有在运行时刻才知道,将对象的创建工作推迟到运行时,这即是优点,有是缺点,失去了编译检查的功能。

    但静态工厂方法又有缺点:

    第一:如果将要创建的对象的构造方法是私有的或是default的,就有可能不能创建该对象。

    ​ 第二:采用构造函数实例化对象,是语言的规范,而静态工厂方法与其他的静态方法没有区别,就增加了用户使用的区别。但这可以尽量采用一些家喻户晓的名字解决,让用户看到改名字就知道该方法是静态工厂方法。如getInstance()。

  13. 未完待续...


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!