Java 面向对象之封装、继承、多态
封装
// 封装 package com.bjpowernode.javase.Java02; /** * 用户类 * @author Administrator * */ public class User { // 年龄 int age; } // ------------------------------------------------------------------------- package com.bjpowernode.javase.Java02; /** * 用户测试类 * * 对于当前程序来说 * User类中的age属性在外部程序中可以随意访问,导致age属性的不安全 * 一个User对象表示一个用户,用户的年龄不可能为负数,一下程序当中年龄值为负数 * 程序运行的时候并没有报错,这是当前程序存在的缺陷。 * * 面向对象包括三大特征: * - 封装 * - 继承 * - 多态 * * 当前主要讲解的是封装机制。为什么要封装?封装有什么好处? * 封装的好处: * 1、封装之后,对于那个事物来说,看不到这个事物比较复杂的那一面,只能看到该事物简单的那一面。 * 复杂性封装,对外提供简单的操作入口。照相机就是一个很好的封装的案例,照相机的实现原理非常复杂,但是对于使用照相机 * 的人来说,操作起来是非常方便的是非常便捷的。还有像电视机也是封装的,电视机内存实现非常复杂,但是对于使用者来说不需要关心内部的实现原理, * 只需要会操作遥控器就行。 * * 2、封装之后才会形成真正的"对象",真正的"独立体" * * 3、封装就是意味着以后的程序可以重复使用。并且这个事物应该适应性比较强,在任何场合都可以使用。 * * 4、封装之后,对于事物本身,提高了安全性。【安全级别高】 */ public class UserTest { public static void main(String[] args) { // 创建user对象 User user = new User(); // 访问age // 读取年龄值【get】 System.out.println("该用户年龄:" + user.age); // 修改年龄值【set】 user.age = 20; // 读取年龄值【get】 // myeclipse快捷键:ctrl + shift + F【请不要用这个快捷键】 System.out.println("该用户年龄:" + user.age); // 修改年齡值 // 这里的age属性显然是完全暴露给外部程序的,对于程序员来说可以操作User对象中所有的细节,导致User中部分数据不安全 // 不建议这样,建议User类型进行封装,建议在外部程序中不能随意访问User对象当中的属性,这样可以保证属性的安全。 user.age = -100; // 读取年龄值 System.out.println("该用户年龄:" + user.age); } }
package com.bjpowernode.javase.Java03; /** * 封装的步骤 * 1、所有属性私有化,使用private关键字进行修饰,private表示私有的,修饰的所有数据只能在本类中访问。 * 2、对外提供简单的操作入口,也就是说以后外部程序要想访问age属性,必须通过这些简单的入口进行访问: * - 对外提供两个公开的方法,分别是set方法和get方法 * - 想修改age属性,调用set方法 * - 想读取age属性,调用get方法 * 3、set方法的命名规范: * public void setAge(int a){ * age = a; * } * 4、get方法的命名规范: * public int getAge(){ * return age; * } * * * 回想一下,一个属性通常访问的时候包括几种访问形式? * - 第一种方式:想读取这个属性的值,读取get * - 第二种方式:想修改这个属性的值,修改set * * 需要大家记住以下内容 * * setter and getter 方法没有static关键字 * * 有static关键字修饰的方法怎么调用:类名.方法名(实参); * * 没有static关键字修饰的方法怎么调用:引用.方法名(实参); */ public class User { // 属性私有化 private int age; // set 方法没有返回值,因为set方法只负责修改数据 /* public void setAge(int age){ age = age; //java有就近原则,这里其实没有给age属性赋值,这里的age都是局部变量age } */ // setter 修改 public void setAge(int a) { // 编写业务逻辑代码进行安全控制 // age = a; if(a < 0 || a >150) { System.out.println("对不起,您提供的年龄不合法"); return; } // 程序可以执行到这里话,说明a年龄是合法的,则进行赋值运算 age = a; } // getter 读取 public int getAge() { return age; } } // ---------------------------------------------------------------------- package com.bjpowernode.javase.Java03; public class UserTest { public static void main(String[] args) { // 创建User对象 User user = new User(); // 编译报错,age属性私有化,在外部程序中不能直接访问 // 从此之后age属性非常的安全,但是有点太安全了 // 对于目前的程序来说,age属性彻底在外部访问不到了。 // System.out.println(user.age); // 修改 user.setAge(-100); // 读取 System.out.println(user.getAge()); } }
package com.bjpowernode.javase.Java03; // 顾客类 public class Customer { // 属性 private int id; private String name; private int age; private String addr; public int getId() { return id; } public void setId(int id) { this.id = id; } 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; } public String getAddr() { return addr; } public void setAddr(String addr) { this.addr = addr; } } // ---------------------------------------------------------------------- package com.bjpowernode.javase.Java03; public class CustomerTest { public static void main(String[] args) { Customer c = new Customer(); // 私有的属性不能在外部直接访问,这就是封装 // c.id = 410; // 操作入口变成了只能通过set和get方法进行访问 // 在set方法和get方法执行过程中可以进行安全过滤 c.setId(100); c.setName("zhangsan"); c.setAge(50); c.setAddr("深圳福田区"); System.out.println(c.getId()); System.out.println(c.getName()); System.out.println(c.getAge()); System.out.println(c.getAddr()); } }
构造方法
package com.bjpowernode.javase.Java04; public class User { // 无参数构造方法 public User() { System.out.println("User's Default Constructor Invoke!"); } // 有参数的构造方法 public User(int i) { System.out.println("带有int类型参数的构造器"); } public User(String name) { System.out.println("带有String类型参数的构造器"); } public User(int i,String name) { System.out.println("带有int,String类型参数的构造器"); } } // ---------------------------------------------------------------------- package com.bjpowernode.javase.Java04; /** * 关于Java类中的构造方法: * 1、构造方法又被成为构造函数/构造器/Constructor * 2、构造方法语法结构: * [修饰符列表] 构造方法名(形式参数列表){ * 构造方法体; * } * 3、回顾普通方法的语法结构: * [修饰符列表] 返回值类型 方法名(形式参数列表){ * 方法体; * } * 4、对于构造方法来说,"返回值类型"不需要指定,并且也不能写void * 只要写上void,那么这个方法就成为普通方法了 * * 5、对于构造方法来说,构造方法的方法名必须和类名保持一致。 * * 6、构造方法的作用: * 构造方法存在的意义是,通过构造方法的调用,可以创建对象。 * * 7、构造方法应该怎么调用? * - 普通方法是这样调用的:方法修饰符中有static的时候:类名.方法名(实参列表)、方法修饰符列表中没有static的时候: 引用.方法名(实参列表) * - new 构造方法名(实参列表) * * 8、构造方法调用执行之后,有返回值吗? * 每一个构造方法实际上执行结束之后都有返回值,但是这个"return 值;"这样的语句不需要写。构造方法结束的时候Java程序自动返回值 * 并且返回值类型是构造方法所在类的类型。由于构造方法的返回值类型就是类本身,所以返回值类型不需要编写。 * * 9、注释和取消注释:ctrl + /,多行注释:ctrl + shift + / * * 10、当一个类中没有定义任何构造方法的话,系统默认给该类提供一个无参数的构造方法,这个构造方法被称为缺省构造器。 * * 11、当一个类显示的将构造方法定义出来了,那么系统则不再默认为这个类提供缺省构造器。建议开发中手动的为当前类提供无参数构造方法。因为无参数构造方法太常用了。 * * 12、构造方法支持重载机制。在一个类当中编写多个构造方法,这个多个构造方法显然已经构造方法重载机制。 */ public class ConstructorTest01 { public static void main(String[] args) { // 创建User对象 // 调用User类的构造方法来完成对象的创建 // 以下程序创建4个对象,只要构造函数调用就会创建对象,并且一定是在"堆内存"中开辟内存空间 User u1 = new User(); User u2 = new User(10); User u3 = new User("zhangsan"); User u4 = new User(10,"zhangsan"); // 调用带有static的方法:类名. ConstructorTest01.doSome(); doSome(); // 调用没有static的方法:引用. // doOther方法在ConstructorTest01类当中,所以需要创建ConstructorTest01对象 // 创建ConstructorTest01对象,调用无参数构造方法 ConstructorTest01 t = new ConstructorTest01(); // 一个类中没有任何构造方法的话,系统默认提供一个无参数构造器 t.doOther(); } public static void doSome(){ System.out.println("do some!"); } public void doOther(){ System.out.println("do other!"); } }
package com.bjpowernode.javase.Java04; // 账户类 public class Account { // 账号 private String actno; // 实例变量/对象变量,也就是说,必须先有对象才能有对应的实例变量 // 余额 private double balance; // 无参数构造器 public Account() { // 初始化实例变量的内存空间 // actno = null // balance = 0.0; } public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } } // ----------------------------------------------------------------------- package com.bjpowernode.javase.Java04; /** * 构造方法的作用: * 1、创建对象 * 2、创建对象的同时,初始化实例变量的内存空间 .【给实例变量赋值】 * 成员变量之实例变量,属于对象级别的变量,这种变量必须先有对象才能有实例变量。 * 实例变量没有手动赋值的时候,系统默认赋值,那么这个系统默认赋值是在什么时候完成的呢? * 是在类加载的时候吗? * 不是,因为类加载的时候只加载了代码片段,还没有来及创建对象,所以此时实例变量并没有初始化 * 实际上,实例变量的内存空间是构造方法执行过程当中完成开辟的。完成初始化的 * 系统在默认赋值的时候,也是在构造方法执行过程当中完成的赋值 * * 实例变量默认值: * byte,short,int,long 0 * float,double 0.0 * bolean false * 引用数据类型 null * * 实例变量是在存储JVM的堆内存java对象内部。 * */ public class ConstructorTest02 { public static void main(String[] args) { // 在myeclipse当中,查看访问的是那个属性,查看访问的是那个方法 // 按ctrl键,鼠标移动到查看的元素上,出现下划线的时候开始单击. // 另外,在一个类当中元素过多,想快速查看,在当前类中使用ctrl + o快捷键,然后输入要查找的元素名称,该名称不一定是输入全名称 // 创建对象 Account act1 = new Account(); System.out.println("账号:" + act1.getActno()); System.out.println("余额:" + act1.getBalance()); } }
package com.bjpowernode.javase.Java04; public class ConstructorTest03 { public static void main(String[] args) { Customer c1 = new Customer(); System.out.println(c1.getNo()); System.out.println(c1.getName()); System.out.println(c1.getBirth()); Customer c2 = new Customer(11111,"zhangsan","1990-10-22"); System.out.println(c2.getNo()); System.out.println(c2.getName()); System.out.println(c2.getBirth()); } } // ---------------------------------------------------------------------- package com.bjpowernode.javase.Java04; /** * myeclipse/eclipse快速编辑,支持多行同时编辑:块编辑 * ctrl + alt + A * */ public class Customer { private int no; private String name; private String birth; // 无参数构造器 public Customer() { } // 有参数构造器 public Customer(int no, String name, String birth) { this.no = no; this.name = name; this.birth = birth; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getBirth() { return birth; } public void setBirth(String birth) { this.birth = birth; } }
对象和应用
1、对象和引用: 1.1、对象和引用的概念? * 对象:目前在使用new运算符在堆内存中开辟的内存空间称为对象。 * 引用:是一个变量,不一定是局部变量,还可能是成员变量。引用保存了内存地址,指向了堆内存当中的对象。 * 所有访问实例相关的数据,都需要通过“引用.”的方式访问,因为只有通过引用才能找到对象。 * 只有一个空的引用,访问对象的实例相关的数据会出现空指针异常。 class Student{ Computer com; //com是一个引用【实例变量】 public static void doSome(){ Computer cc; //cc是一个引用【局部变量】 } } 1.2、参数的传递? 主要研究和学习的是方法在调用的时候,涉及到参数传递的问题,到底是怎么传递数据的呢? 值传递。 int i = 10; int j = i; //i传递给j,实际上只是将i变量中保存的10传递给j了,j实际上是一块全新的内存空间。 User u = 0x1234; User u2 = u; //u传递给u2,实际上是将0x1234这个值赋值给u2了,u和u2实际上是两个不同的局部变量, //但是它们这两个变量指向堆内存中同一个java对象。
package com.bjpowernode.javase.Java04; /** * Java语言当中方法调用的时候涉及到参数传递的问题 * 参数传递实际上传递的是变量中保存的具体值 * * int = 10; * add(i); 等同于:add(10); */ public class Test01 { public static void main(String[] args) { int i = 10; add(i); // add方法调用的时候,给add方法传递一个变量i,到底传的是什么? System.out.println("main --> " + i); // 10 } public static void add(int i) { i++; System.out.println("add --> " + i); // 11 } }
package com.bjpowernode.javase.Java05; /* * 最终结论: * 方法调用的时候,涉及到参数传递的问题,传递的时候,java只遵循一种语法机制 * 就是将变量中保存的“值”传递过去了,只不过有的时候这个值是一个字面值10,有的时候 * 这个值是另一个java对象的内存地址0x1234 */ public class Test02 { public static void main(String[] args) { // User u = 0x1234 User u = new User(20); // 传递u给add方法的时候,实际上传递的是u变量中保存的值,只不过这个值是一个java对象的内存地址 add(u); // 等同于:add(0x1234); System.out.println("main -->"+ u.age); } public static void add(User u) { u.age++; System.out.println("add -->"+ u.age); } } class User{ // 实例变量 int age; // 构造方法 public User(int i) { age = i; } }
this关键字
package com.bjpowernode.javase; /** * 关于Java语言中的this关键字: * 1、this是一个关键字,翻译为:这个 * 2、this是一个引用,this是一个变量,this变量中保存了内存地址指向了自身,this存储在JVM堆内存java对象内部 * 3、创建100个java对象,每一个对象都有this,也就是说有100个不同的this * 4、this可以出现在"实例方法"当中,this指向当前正在执行这个动作的对象。(this代表当前的对象) * 5、this在多数情况下都是可以省略不写的 * 6、this不能使用在带有static的方法当中 */ public class Customer { // 姓名【堆内存的对象内部中存储,所以访问该数据的时候,必须先创建对象,通过引用方式访问】 String name; // 实例变量:必须采用“应用.”的方式访问 // 构造方法 public Customer() { } // 不带有static关键字的一个方法 // 顾客购物的行为 // 每一个顾客购物最终的结果是不一样的 // 所以购物这个行为是属于对象级别的行为 // 由于每一个对象在执行购物这个动作的时候最终的结果不同,所以购物这个动作必须有“对象”的参与。 // 重点:没有static关键字的方法被成为“实例方法”,实例方法怎么访问?“引用.” // 重点:没有static关键字的方法被成为“实例变量” // 注意:当一个行为/动作执行的过程当中是需要对象参与的,那么这个方法一定要定义为“实例方法”,不要static关键字 // 以下方法定义为实例方法,因为每一个顾客在真正购物的时候,最终的结果是不同的。所以这个动作在完成的时候必须有对象的参与。 public void shopping() { // 当张三在购物的时候,输出:张三在购物 // 当李四在购物的时候,输出:李四在购物 // System.out.println("xxx在购物!"); // 由于name是一个实例变量,所以这个name访问的时候一定访问的是当前对象的name // 所以多数情况下“this.”是可以省略的。 System.out.println(name + "在购物!"); // 完整写法 // System.out.println(this.name + "在购物!"); } // 带有static public static void doSome() { // 这个执行过程中没有“当前对象”,因为带有static的方法是通过类名的方式访问的 // 或者说这个“上下文”当中没有“当前对象”,自然也不存在this(this代表的是当前正在执行这个动作的对象) // 以下程序为什么编辑错误呢? // doSome方法调用不是对象去调用,是一个类名去调用,执行过程中没有“当前对象” // name是一个“实例变量”,以下代码的含义是:访问当前对象的name,没有当前对象,自然也不能访问当前对象的name // System.out.println(name); // static的方法调用不需要对象,直接使用类名,所以执行过程中没有当前对象,所以不能使用this // System.out.println(this); } public static void doOther() { // 假设想访问name这个实例变量的话应该怎么做? // System.out.println(name); // 编译报错 // 可以采用以下方案,但是以下方案,绝对不是访问的当前对象的name // 创建对象 Customer c = new Customer(); c.name = "jack"; System.out.println(c.name); // 这里访问的name是c引用指向对象name } } // ----------------------------------------------------------------------- package com.bjpowernode.javase; public class CustomerTest { public static void main(String[] args) { // 创建Customer对象 Customer c1 = new Customer(); c1.name = "张三"; // c1购物 c1.shopping(); // 再创建Customer对象 Customer c2 = new Customer(); c2.name = "李四"; // c2购物 c2.shopping(); // 调用doSome方法(修饰符列表上有static) // 采用“类名.”的方式访问,显然这个方法在执行的时候不需要对象的参加。 Customer.doSome(); // 调用doother Customer.doOther(); } }
package com.bjpowernode.javase; public class ThisTest { // 实例变量(引用.的方式访问) int num = 10; // 带有static的方法 // JVM负责调用main方法,JVM是怎么调用的? // ThisTest.main(String[]); public static void main(String[] args) { // 没有当前对象this // 以下代码是什么意思? // 访问“当前对象”的num属性 // ystem.out.println(this.num); // 编译错误 // System.out.println(n.num); // 编译错误 // 想访问num怎么办? ThisTest tt = new ThisTest(); System.out.println(tt.num); } }
package com.bjpowernode.javase; /** * 最终结论: * 在带有static的方法当中不能“直接”访问实例变量和实例方法 * 因为实例变量和实例方法都需要对象的存在 * 而static的方法当中是没有this的,也就是说当前对象是不存在的 * 自然也是无法访问的当前对象的实例变量和实例方法 */ public class ThisTest01 { // 带有static // 主方法 public static void main(String[] args) { // 调用doSome方法 ThisTest01.doSome(); // 调用doSome方法 doSome(); // 调用dother方法 // 【编译错误】 // ThisTest.doOther(); // 实例方法必须先创建对象,通过引用.的方式访问 // doOther是实例方法 // 实例方法调用的必须有对象的存在 // 以下代码表示的含义:调用当前对象的doOther方法 // 但是由于main方法中没有this,所以以下方法不能调用 // doOther(); // 编译错误 // this.doOther(); // 编译错误 ThisTest01 tt = new ThisTest01(); tt.doOther(); tt.run(); } // 带有static public static void doSome() { System.out.println("do some!"); } // 实例方法 public void doOther() { // this表示当前对象 System.out.println("do other!"); } // run是实例方法,调用run方法的一定是有对象存在的 // 一定是先创建了一个对象才能调用run方法 public void run() { // 在大括号中的代码执行过程当中一定是存在“当前对象”的 // 也就是说这里一定是有“this”的。 System.out.println("run execute!!"); // doOther是一个实例方法,实例方法调用必须有对象的存在 // 以下代码表示的含义就是:调用当前对象的doOther方法 doOther(); // this. 大部分情况下都可以省略的 // this.doOther(); // 比较完整的写法 } }
package com.bjpowernode.javase; /* * "this."什么时候不能省略? * 用来区分局部变量和实例变量的时候,“this.”不能省略。 * */ // 用户类 public class User { // 属性 private int id; // 实例变量 private String name; // 构造函数 public User() {} public User(int id ,String name) { this.id = id; this.name = name; } // setter and getter // public void setId(int a) { // id = a; // } // 以下程序的id和实例变量id无关,不能采用这种方式 /* public void setId(int id) { id = id; } */ /* public void setId(int id) { // 等号前边的this.id实例变量id // 等号后面的id是局部变量的id this.id = id; } */ public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } } // ----------------------------------------------------------------------- package com.bjpowernode.javase; public class UserTest { public static void main(String[] args) { User u1 = new User(100,"张三"); System.out.println(u1.getId()); System.out.println(u1.getName()); // 想修改名字 u1.setName("李四"); System.out.println(u1.getName()); } }
package com.bjpowernode.javase; /** * 自定义的日期类型 * * this 可以用在哪里? * 1、可以使用在实例方法当中,代表当前对象【语法格式:this.】 * 2、可以使用在构造方法当中,通过当前的构造方法调用其它的构造方法【语法格式:this(实参);】 * 重点【记忆】:this()这种语法只能出现构造函数第一行。 */ public class Date { // 属性 private int year; private int month; private int day; // 构造函数 public Date(int year, int month, int day) { this.year = year; this.month = month; this.day = day; } /** * 需求:当程序员调用以下无参数的构造方法的时候,默认创建的日期是:1970-1-1 */ public Date() { /* this.year = 1970; this.month = 1; this. day = 1; */ // 以上代码可以通过调用另一个构造方法来完成 // 但前提是不能创建新的对象,以下代码表示创建了一个全新的对象 // new Date(1970,1,1); // 需要采用以下的语法来完成构造方法的调用 // 这种方式不会创建新的java对象。但同时有可以达到调用其他的构造方法 this(1970,1,1); } // setter and getter public int getYear() { return year; } public void setYear(int year) { this.year = year; } public int getMonth() { return month; } public void setMonth(int month) { this.month = month; } public int getDay() { return day; } public void setDay(int day) { this.day = day; } // 对外提供一个方法可以将日期打印输出到控制台 // 实例方法 public void print() { System.out.println(this.year + "年" + this.month + "月" + this.day + "日"); } } // ----------------------------------------------------------------------- package com.bjpowernode.javase; public class DateTest { public static void main(String[] args) { // 创建日期对象1 Date time1 = new Date(); time1.print(); // 创建日期对象2 Date time2 = new Date(2021,7,14); time2.print(); } }
总结
package com.bjpowernode.javase; public class Test { // 没有static的变量 int i = 10; // 带有static的方法 public static void doSome() { System.out.println("do some!"); } // 没有static的方法 public void doOther() { System.out.println("do other!"); } // 带有static方法 public static void method1() { // 调用doSome // 完整方式的调用 Test.doSome(); // 省略方式的调用 doSome(); // 调用doOther // 完整方式的调用 Test d = new Test(); d.doOther(); // 省略方式的调用 // 访问i // 完整方式的调用 System.out.println(d.i); // 省略方式的调用 } // 没有static的方法 public void method2() { // 调用doSome // 完整方式的调用 Test.doSome(); // 省略方式的调用 doSome(); // 疑问 // 调用doOther // 完整方式的调用 this.doOther(); // 省略方式的调用 doOther(); // 访问i // 完整方式的调用 System.out.println(this.i); // 省略方式的调用 System.out.println(i); } // 主方法 public static void main(String[] args) { // 要求在这里编写程序调用method1 // 使用完整方式调用 Test.method1(); // 使用省略方式调用 method1(); // 要求在这里编写程序调用method2 // 使用完整方式调用 Test ddd = new Test(); ddd.method2(); // 使用省略方式调用 } }
package com.bjpowernode.javase; /** * 什么时候程序在运行的时候出现空指针异常呢? * 空引用访问示例相关的数据,因为实例相关的数据就是对象相关的数据 * 这些数据在访问的时候,必须有对象的参与,当空引用的时候,对象不存在, * 访问这些的实例数据就一定会出现空指针异常 * * 实例相关的数据包括: * 实例变量【对象需要存在】 * 实例方法【对象需要存在】 */ public class Test { public static void main(String[] args) { Test.doSome(); doSome(); Test t = new Test(); t.doSome(); // 引用是空 t = null; // 带有static的方法,其实既可以采用类名的方式访问,也可以采用引用的方式访问 // 但是即使采用引用的方式去访问,实际上执行的时候和引用指向的对象无关。 // 在myeclipse中方法还是建议使用"类名."的方式访问 t.doSome(); // 这里不会出现空指针异常 } // 带有static的方法,需要使用"类名."的方式访问 public static void doSome() { System.out.println("do Some!"); } }
static 关键字
package com.bjpowernode.javase01; /** * "中国人"类 * */ public class Chinese { // 身份证号【每一个对象的身份证不同】 // 实例变量 String id; // 姓名【每一个对象的姓名不同】 // 实例变量 String name; // 国籍【每一个对象由于都是由"Chinese类"实例化的,所以每一个中国人的国籍都是"中国"】 // 无论通过Chinese类实例化多少个java对象,这些java对象的国籍都是"中国" // 实例变量【实例变量是一个java对象就有一份,100个java对象,就有100个country】,分析这种设计方式有什么缺点? // 实例变量存储java对象内部,在堆内存当中,在构造方法执行的时候初始化 // 所以的中国人的国籍都是"中国",这里声明为实例变量显然是不合适的,太浪费内存空间,没必要让每个对象都保留一份"国籍"内存。 String country; // 构造方法 public Chinese() { } public Chinese(String id,String name, String country) { this.id = id; this.name = name; this.country = country; } } // ----------------------------------------------------------------------- package com.bjpowernode.javase01; public class ChineseTest { public static void main(String[] args) { // 创建中国人对象1 Chinese zhangsan = new Chinese("1","张三","中国"); System.out.println(zhangsan.id + "," + zhangsan.name + "," + zhangsan.country); // 创建中国人对象2 Chinese lisi = new Chinese("2","李四","中国"); System.out.println(lisi.id + "," + lisi.name + "," + lisi.country); } }
package com.bjpowernode.javase01; /** * 什么时候成员变量声明为实例变量呢? * - 所有对象都有这个属性,但是这个属性的值会跟着对象的变化而变化【不同对象的这个属性具体的值不通】 * 什么时候成员变量声明为静态变量呢? * - 所有对象都有这个属性,并且所有对象的这个属性的值是一样的,建议定义为静态变量,节省内存的开销 * * 静态变量的类加载的时候初始化,内存在方法区中开辟。访问的时候不需要创建对象,直接使用"类名.静态变量名"的方式访问 * * 关于Java中的static关键字: * 1、static英语单词编译为静态的 * 2、static修饰的方法是静态方法 * 3、static修饰的变量是静态的变量 * 4、所有static修饰的元素都成为静态的,都可以使用"类名."的方式访问,当然也可以用引用.的方式访问【但不建议】 * 5、static修饰的所有元素都是类级别的特征,和具体的对象无关。 */ public class Chinese { // 身份证号【每一个对象的身份证不同】 // 实例变量 String id; // 姓名【每一个对象的姓名不同】 // 实例变量 String name; // 国籍【所有对象国籍一样,这种特征属于类级别的特征,可以提升为整个模板的特征,可以变量前添加static关键字修饰】 // 静态变量,静态变量在类加载的时候初始化,不需要创建对象,内存就开辟了 static String country = "中国"; // 构造方法 public Chinese() { } public Chinese(String id,String name) { this.id = id; this.name = name; } } // ----------------------------------------------------------------------- package com.bjpowernode.javase01; public class ChineseTest { public static void main(String[] args) { // 创建中国人对象1 Chinese zhangsan = new Chinese("1","张三"); System.out.println(zhangsan.id + "," + zhangsan.name + ","+ Chinese.country); // 创建中国人对象2 Chinese lisi = new Chinese("2","李四"); System.out.println(lisi.id + "," + lisi.name + ","+ Chinese.country); System.out.println(Chinese.country); // 所有静态的数据都是可以采用类名.,也可以采用引用. , 但是建议采用类名.的方式访问 // 采用引用. 的方式访问的时候,即使引用是null,也不会出现空指针异常,因为访问静态的数据不需要对象的存在 // System.out.println(zhangsan.country); } }
package com.bjpowernode.javase01; /** * 可以使用static关键字来定义"静态代码快": * 1、语法格式: * static{ * java语句 * } * 2、静态代码快在类加载时执行,并且只能执行一次。 * * 3、静态代码块在一个类中可以编写多个,并且遵循自上而下的顺序依次执行 * * 4、静态代码块的作用什么?怎么用?用在哪里?什么时候用? * - 这当然和具体的需求有关,例如项目中要求在类加载的时刻/时机执行代码完成日志的记录 * 那么这段记录日志的代码就可以编写到静态代码块当中,完成日志记录。 * - 静态代码块是java为程序员准备一个特殊的时刻,这个特殊的时刻被称为类加载时刻,若 * 希望在此刻执行一段特殊的程序,这段程序可以直接放到静态代买块当中 * 5、通常在静态代码块当中完成预备工作,先完成数据的准备工具,例如:初始化连接池,解析XMI配置文件.... * * */ public class StaticTest01 { static { System.out.println("类加载-->1"); } static { System.out.println("类加载-->2"); } static { System.out.println("类加载-->3"); } public static void main(String[] args) { System.out.println("main begin"); } }
package com.bjpowernode.javase01; /** * 实例语句块/代码快【了解内容,使用的非常少】 * 1、实例代码块可以编写多个,也是遵循智商而下的顺序依次执行 * 2、实例代码块在构造方法执行之前执行,构造方法执行依次,实例代码块对应执行一次 * 3、实例代码快也是java语言为程序员准备一个特殊的时机,这个特殊时机被称为:对象初始化时机 * */ public class Test { // 构造函数 public Test(){ System.out.println("Test类的缺省构造器执行"); } // 实例代码块 { System.out.println(1); } // 实例代码块 { System.out.println(2); } // 实例代码块 { System.out.println(2); } public static void main(String[] args) { System.out.println("main begin"); new Test(); new Test(); } }
package com.bjpowernode.javase01; /** * 方法什么时候定义为静态的? * 方法描述的是动作,当所有的对象执行这个动作的时候,最终产生影响是一样的,那么 * 这个动作已经不在属于某一个对象的动作了,可以将这个动作提升为类级别的动作,模板 * 级别的动作 * * 静态方法中无法直接访问示例变量和实例方法 * * 太多数方法都定义为实例方法,一般一个行为或者一个动作在发生的时候,都需要对象的参与。 * 但是也有例外,例如:太多数“工具类”中的方法都是静态方法,因为工具类就是方便编程,为了 * 方便方法的调用,自然不需要new对象是最好的 */ public class StaticTest { // 实例变量 int i =100; // 实例方法 public void doSome() { } // 静态方法【静态上下文】 public static void main(String[] args) { // System.out.println(i); // doSome(); StaticTest st = new StaticTest(); System.out.println(st.i); st.doSome(); } } /* * 总结: * class类{ * 静态代码快; * 实例代码快; * * 静态变量 * 实例变量 * * 构造方法 * * 静态方法 * 实例方法 * } */
继承
package com.bjpowernode.javase02; /** * 关于Java语言当中的继承: * 1、继承是面向对象三大特征之一,三大特征分别是:封装、继承、多态 * 2、继承基本的作用是:代码复用。但是继承最重要的作用是:有了继承才有了以后"方法的覆盖"和"多态机制" * 3、继承语法格式: * [修饰符列表] class 类名 extends 父类名{ * 类体 = 属性 + 方法 * } * 4、java语言当中的继承只支持单继承,一个类不能同时继承很多类,只能继承一个类,在C++中支持多继承 * 5、关于继承中的一些术语; * B类继承A类,其中: * A类称为:父类、基类、超类、superclass * B类称为:子类、派生类、subclass * 6、在java语言当中子类继承父类都继承那些数据呢? * - 私有的不支持继承 * - 构造方法不支持继承 * - 其它数据都可以被继承 * 7、虽然java语言当中只支持单继承,但是一个类也可以问接继承其它类,例如: * C extends B{ * } * B extends A{ * } * A extends T{ * } * C直接继承B类,但是C类间接继承T、A类。 * * 8、java语言中假设一个类没有显示的继承任何类,该类默认继承JavaSE库当中提供的java.lang.Object类。 * Java语言中任何一个类中都有Object类的特征。 * * * */ public class ExtendsTest { // MyEclipse快捷键:查找类型【Open Type】-->ctrl + shift + t // MyEclipse快捷键:查找资源【Open Resource】-->ctrl + shift + r public static void main(String[] args) { ExtendsTest et = new ExtendsTest(); // 这里编译通过了,这说明可以调用toString方法,ExtendsTest类中有toString,从Object类中继承过来的 String s = et.toString(); // com.bjpowernode.javase02.ExtendsTest@15db9742 System.out.println(s); CreditAccount act = new CreditAccount(); act.setActno("act-001"); act.setBalance(-1000.0); act.setCredit(0.99); System.out.println(act.getActno() + "," + act.getBalance()+ ","+act.getCredit()); } } // ----------------------------------------------------------------------- package com.bjpowernode.javase02; public class Account { private String actno; private double balance; public Account() { } public Account(String actno, double balance) { super(); this.actno = actno; this.balance = balance; } public String getActno() { return actno; } public void setActno(String actno) { this.actno = actno; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } } // ----------------------------------------------------------------------- package com.bjpowernode.javase02; public class CreditAccount extends Account { private double credit; public CreditAccount() { } public double getCredit() { return credit; } public void setCredit(double credit) { this.credit = credit; } }
package com.bjpowernode.javase02; public class ExtendsTest02 { public static void main(String[] args) { C c = new C(); c.doSome(); // 这里调用的doSome方法是从B类中继承过来的doSome方法 } } class A{ public void doSome() { System.out.println("do some!"); } } class B extends A{ public void doSome() { System.out.println("~~~~do some!~~~"); } } class C extends B{ public void doSome() { System.out.println("~~~C~do some!~~~"); } }
方法的覆盖
package com.bjpowernode.javase02; // 动物类 public class Animal { // 动物都是可以移动的 public void move() { System.out.println("动物在移动"); } } // ------------------------------------------------------------------------- package com.bjpowernode.javase02; // 猫科类 public class Cat extends Animal{ public void move() { System.out.println("小猫在奔跑"); } } // ---------------------------------------------------------------------- package com.bjpowernode.javase02; // 飞禽类 public class Bird extends Animal { public void move() { System.out.println("鸟儿在飞翔"); } } // --------------------------------------------------------------------- package com.bjpowernode.javase02; public class YingWu extends Bird { // 这里的move方法覆盖的是Bird当中的move方法 public void move() { System.out.println("鹦鹉飞不起来!"); } } // ---------------------------------------------------------------------- package com.bjpowernode.javase02; /** * 回顾java语言当中的重载 * 1、方法重载又称为Overload * 2、方法重载什么时候使用? * 当在同一个类当中,方法完成的功能是相似的,建议方法名相同,这样方便程序员的编程 * 3、什么条件满足之后构成方法重载? * * 在同一个类当中 * * 方法名相同 * * 参数列表不同:类型、顺序、个数 * 4、方法重载和什么无关? * * 和方法的返回值类型无关 * * 和方法的修饰符列表无关 * * 关于Java语言当中方法的覆盖: * 1、方法覆盖又被成为方法重写,英语单词:override【官方的】/overwrite * 2、什么时候使用方法重写? * 当父类中的方法已经无法满足当前之类的业务需求 * 之类有必要将父类中继承过来的方法进行重新编写 * 这个重写编写的过程称为方法重写/方法覆盖。 * 3、什么条件满足之后方法会发生重写呢?【代码满足什么条件之后,就构成方法的覆盖呢?】 * * 方法重写发生在具有继承父系的类之间 * * 方法重写的时候:返回值类型相同,方法名相同,形参列表相同 * * 方法重写的时候:访问权限不能更低,可以更高 * * 方法重写的时候:抛出异常不能更多,可以更少 * 4、建议方法重写的时候尽量复制粘贴,不要编写,容器出错,导致没有产生覆盖。 * 5、注意: * 私有方法不能继承,所有不能覆盖 * 构造方法不能继承,所以不能覆盖 * 静态方法不存在覆盖。【】 */ public class OverrideTest01 { public static void main(String[] args) { // 创建动物对象 Animal a = new Animal(); a.move(); // 创建猫科类动物对象 Cat c = new Cat(); c.move(); // 创建飞禽类动物对象 Bird b = new Bird(); b.move(); YingWu y = new YingWu(); y.move(); } }
多态
package com.bjpowernode.javase03; /** * 关于语言当中的多态语法机制: * 1、Animal、Cat、Bird三个类之间的关系 * Cat继承Animal * Bird继承Animal * Cat和Bird之间没有任何继承关系 * 2、面向对象三大特征:封装、继承、多态 * * 3、关于多态中涉及到的几个概念: * * 向上转型(upcasting) * - 子类型 ——>父类型 * 又被成为:自动类型转换 * * 向下转型(downcasting) * - 父类型 ——>子类型 * 又被称为:强制类型转换。【需要加强制类型转换符】 * * 需要记忆: * 无论是向上转型还是向下转型,两种类型之间必须要又继承关系。 * 没有继承关系,程序是无法编译通过的 * */ public class Test { public static void main(String[] args) { // 以前编写的程序 Animal a1 = new Animal(); a1.move(); Cat c1 = new Cat(); c1.move(); c1.catchMouse(); Bird b1 = new Bird(); b1.move(); // 使用多态语法机制 /** * 1、Animal和Cat之间存在继承关系,Animal是父类,Cat是之类 * * 2、Cat is a Animal【合理的】 * * 3、new Cat()创建的对象的类型是Cat,a2这个引用的数据类型是Animal,可见他们进行了类型转换 * 子类型转换成父类型,称为向上转型/upcasting,或者称为自动类型转换 * * 4、Java中允许这种语法:父类型引用指向子类型对象 */ Animal a2 = new Cat(); // Bird b2 = new Cat(); // 编译报错,因为两种类型之间不存在任何继承关系,无法向上或者向下转型 /** * 1、JAVA程序永远都分为编译阶段和运行阶段 * 2、先分析编译阶段,在分析运行阶段,编译无法通过,根本是无法运行的 * 3、编译阶段编译器检查a2这个引用的数据类型为Animal,由于Animal.class * 字节码当中有move()方法,所以编译通过了,这个过程我们称为静态绑定,编译阶段绑定,只有静态绑定成功之后才有后续的运行 * 4、在程序运行阶段,JVM对内存当中真实创建的对象是Cat对象,那么一下程序在运行阶段 * 一定会调用Cat对象的move()方法,此时发生了程序的动态绑定,运行阶段绑定。 * 5、无论是Cat类有没有重写move方法,运行阶段一定调用是Cat对象的move方法,因为底层正式对象就是Cat对象 * 6、父类型引用指向子类型对象这种机制导致程序存在编译阶段绑定和运行阶段绑定两种不同的形态/状态,这种机制可以成为一种多态语法机制 */ a2.move(); /** * 分析以下程序为什么不能调用? * 因为编译阶段编译器检查到a2的类型是Animal类型 * 从Animal.class字节码文件当中查找catchMouse(( * 方法,最终没有找到该方法,导致静态绑定失败,没有班定成功 * 也就是说编译失败了,运行不了。 */ // a2.catchMouse(); /** * 需求: * 假设想以上的对象执行catchMouse()方法,怎么办? * a2是无法直接调用的,因为a2的类型Animal,Animal中没有catchMouse()方法 * 我们可以将a2强制类型转换为Cat类型 * a2的类型是Animal(父类),转换成Cat类型(子类),被称为向下转型/downcasting/强制类型转换 * * 注:向下转型也需要两种类型之间必须有继承关系,不然编译报错,强制类型转换需要加强制类型转换符。 * * 什么时候需要使用向下转型呢? * 当调用的方法是子类型中持有的,在父类型当中不存在,必须进行向下类型 */ Cat c2 = (Cat)a2; c2.catchMouse(); c2.move(); // 父类型引用指向子类型对象【多态】 Animal a3 = new Bird(); /** * 1、以下程序编译是没有问题的,因为编译器检查到a3的数据类型是Animal * Animal和Cat之间存在继承关系,并且Animal是父类型,Cat是子类型 * 父类转换成子类型叫做向下转型,语法合格 * * 2、程序虽然编译通过了,但是程序在运行阶段会出现异常,因为JVM堆内存 * 当中真实存在的对象是Bird类型,Bird对象无法转换成Cat对象,因为两种 * 类型之间不存在任何继承关系,此时出现了著名的异常: * java.lang.ClassCastException * 类型转换异常,这种异常总是在"向下转型"的时候会发生 */ // Cat c3 = (Cat)a3; /** * 1、以上异常只有在强制类型转换的时候发生,也就是说"向下转型"存在隐患(编译过了,但是运行错了!) * 2、向上转型只要编译通过,运行一定不会出问题,Animal a = new Cat(); * 3、向下转型编译通过,运行可能错误:Animal a3 = new Bird(); Cat c3 = (Cat)a3; * 4、怎么避免向下转型出现的ClassCaseException呢? * 使用instanceof运算符可以避免出现以上异常 * 5、instanceof运算符真没用? * 5.1、语法格式: * (引用 instancef 数据类型名) * 5.2、以上运算符的执行结果类型是布尔类型,结果可能是true/false * * 5.3、关于运算符结果true/false * 假设:(a instanceof Animal) * true表示: * a这个引用指向的对象是一个Animal类型 * false表示: * a这个引用指向的对象不是一个Animal类型 * 6、Java规范中要求:在进行强制类型转换之前,建议采用instanceof运算符进行判断,避免ClassCaseException异常的发生,这是一种编程好习惯 */ System.out.println("--------------------------------------"); if(a3 instanceof Cat) { // a3是一个Cat类型的对象 Cat c3 = (Cat)a3; // 调用之类对象中特有的方法 c3.catchMouse(); }else if(a3 instanceof Bird) { // a3是一个Bird类型的对象 Bird b2 = (Bird)a3; // 调用之类对象中特有的方法 b2.fly(); } } } // ------------------------------------------------------------------------ package com.bjpowernode.javase03; public class Test2 { public static void main(String[] args) { // 父类型引用指向之类型对象 // 向上转型 Animal a1 = new Cat(); Animal a2 = new Bird(); // 向下转型【只有当访问之类对象当中持有的方法】 if (a1 instanceof Cat) { Cat c1 = (Cat)a1; c1.catchMouse(); }else if (a2 instanceof Bird) { Bird c2 = (Bird)a2; c2.fly(); } } } // ----------------------------------------------------------------------- package com.bjpowernode.javase03; // 动物类 public class Animal { public void move() { System.out.println("动物在移动"); } } // ---------------------------------------------------------------------- package com.bjpowernode.javase03; public class Cat extends Animal { // 重写父类中继承过来的方法 public void move() { System.out.println("猫在走猫步!"); } // 不是从父类中继承过来的方法 // 这个方法是之类对象特有的行为【不是说有的动物都能抓老鼠】 public void catchMouse() { System.out.println("猫抓老鼠"); } } // ----------------------------------------------------------------------- package com.bjpowernode.javase03; // 鸟儿类 public class Bird extends Animal { // 重写父类中继承过来的方法 public void move() { System.out.println("鸟儿在飞翔!"); } // 子类对象特有的行为/动作 public void fly() { System.out.println("Bird fly!"); } }
扩展力强,耦合度低
package com.bjpowernode.Java01; /* * 多态在实际开发中的作用,以下以主人喂养宠物为例说明多态的作用 * 1、分析:主人喂养宠物这个场景要实现需要进行类型的抽象: * - 主人【类】 * - 主人可以喂养宠物,所以主人有喂养的这个动作 * - 宠物【类】 * - 宠物可以吃东西,所以有吃东西的这个重做 * * 2、面向对象编程的核心: 定义好类,然后将类实例化为对象,给一个环境驱使一下,让各个对象之间写作起来形成一个系统 * 3、多态的作用是什么? * 降低程序的耦合度,提高程序的扩展力 * 能使用多态尽量使用多态 * 父类型引用指向子类型对象 * 核心:面向抽象编程,尽量不要面向具体编程。 */ public class Test { public static void main(String[] args) { // 创建主人对象 Master zhangsan = new Master(); // 创建猫对象 // Cat tom = new Cat(); // 主人喂养猫 // zhangsan.feed(tom); zhangsan.feed(new Cat()); // 创建小狗对象 // Dog erha = new Dog(); // 主人喂小狗 // zhangsan.feed(erha); zhangsan.feed(new Dog()); // 创建蛇对象 Snake mangShe = new Snake(); // 主人喂猛蛇 zhangsan.feed(mangShe); zhangsan.feed(new Snake()); } } // --------------------------------------------------------------------- package com.bjpowernode.Java01; /** * 主人 * */ //降低程序的耦合度【解耦合】,提高程序的扩展力【软件开发的一个很重要的目标】 public class Master { /** * 喂养宠物的发放 */ // 这种方式没有使用java语言当中的多态机制,存在缺点:Master的扩展力很差,因为只要加一个新的宠物,Master类就需要添加新方法 /* public void feed(Cat c) { System.out.println("主人喂养!"); c.eat(); } public void feed(Dog d) { System.out.println("主人喂养!"); d.eat(); } // Master和Cat、Dog这两个类型关联程度很强,耦合度很高,扩展力很差。 */ // Master主人类面向的是一个抽象的Pet,不再面向具体的宠物 // 提倡:面向抽象编程,不要面向具体编程 // 面向抽象编程的好处是,耦合度低,扩展力强 public void feed(Pet pet) { // Pet pet是一个父类型的引用 System.out.println("主人喂养!"); pet.eat(); } } // ----------------------------------------------------------------------- package com.bjpowernode.Java01; /** * 宠物类,抽象出来的一个类型 * @author Administrator * */ public class Pet { /** * 宠物都可以吃东西 */ public void eat() { } } // ----------------------------------------------------------------------- package com.bjpowernode.Java01; /** * 宠物小猫 * */ public class Cat extends Pet { // 小猫在吃鱼 public void eat() { System.out.println("小猫正在吃鱼!"); } } // ----------------------------------------------------------------------- package com.bjpowernode.Java01; /** * 宠物小狗 * */ public class Dog extends Pet { /** * 宠物小狗喜欢吃骨头 */ public void eat() { System.out.println("小狗正在啃骨头!"); } } // ---------------------------------------------------------------------- package com.bjpowernode.Java01; // 新的宠物 public class Snake extends Pet { public void eat() { System.out.println("蛇吞象!"); } }
final关键字
package com.bjpowernode.Java02; /** * 关于Java语言中final关键字 * 1、final是一个关键字,表示最终的,不可变的 * 2、final修饰的类无法被继承 * 3、final修饰的方法无法被覆盖 * 4、final修饰的变量"一旦"赋值之后,不可重新赋值【不可二次赋值】 * 5、final修饰的实例变量,必须手动赋值,不能采用系统默认值 * 6、final修饰的引用,一旦指向某个对象之后,不能在指向其它对象,那么被指向的对象无法被垃圾回收器回收 * final修饰的引用虽然指向某个对象不能指向其它对象,但是所指向的对象内部的内存是可以被修改的
* 7、final修饰的实例变量,一般和static联合使用,被称为常量。 * 关于myeclipse怎么链接源码? * 打开某个.class字节码文件,当没有看到源码的时候: * 点击"Attached Source": * - Workspace 【源码在当前的工作区当中】 * - External File 【源码在某个压缩包当中】 * - External Folder 【源码在某个目录当中】 * * 以后尽量所有的程序都链接源码,没有源码从网上找,或者跟老师要源码。 * 养成看源代码的好习惯 * * 对于以后大家所学习的类库,一般都是包括三个部分的 * - 源码【可以看源码来理解程序】 * - 字节码【程序开发的过程中使用的就是这部分】 * - 帮助文档【对源码的解释说明被提取出来,更方便程序的开发】 * 注意使用的时候版本的统一 */ public class FinalTest01 { public static void main(String[] args) { int i = 10; System.out.println(i); i = 20; System.out.println(i); final int k = 100; // 编译错误:无法为最终变量k分配值 // k = 300; final int m; m = 200; // 编译错误:无法为最终变量k分配值 // m = 200; } } // ----------------------------------------------------------------------- package com.bjpowernode.Java02; public class FinalTest02 { // 成员变量之实例变量 // 实例变量有默认值 + final修饰的变量一旦赋值不能重新赋值 // 综合考虑,java语言最终规定实例变量使用final修饰之后,必须手动赋值,不能采用系统默认值 // final int age; // 编译错误 // 第一种解决方案 final int age = 10; // 第二种解决方案 final int num; public FinalTest02() { this.num = 200; } // 以上的两种解决方案:其实本质上就是一种方式,就是在构造方法执行过程当中给实例变量赋值 public static void main(String[] args) { final int a; a =100; // 不可二次赋值 // a =200; } } // ----------------------------------------------------------------------- package com.bjpowernode.Java02; public class FinalTest03 { public static void main(String[] args) { // 创建用户对象 User u = new User(100); // 有创建了一个新的User对象 // 程序执行到此处表示以上对象已变成垃圾数据,等待垃圾回收期的回收 u = new User(200); // 创建用户对象 final User user = new User(30); System.out.println(user.id); // user = new User(50); // final修饰的引用,一旦指向某个对象之后,不能在指向其它对象,那么被指向的对象无法被垃圾回收器回收 user.id = 50; // final修饰的引用虽然指向某个对象不能指向其它对象,但是所指向的对象内部的内存是可以被修改的 System.out.println(user.id); } } // ----------------------------------------------------------------------- package com.bjpowernode.Java02; public class User { int id; public User(int id) { super(); this.id = id; } }
package com.bjpowernode.Java02; public class FinalTest04 { public static void main(String[] args) { System.out.println(Chinese.GUO_JI); System.out.println("圆周率:" + Math.PI); } } class Mateh{ public static final double PI = 3.1415926; } // 中国人 class Chinese { // 国籍 // 每一个中国人国籍都是中国,而且国籍不会发生改变,为了防止国籍被修改,建议加final修饰。 // final修饰符的实例变量是不可变的,这种变量一般和static联合使用,被成为"常量" // 常量的定义语法格式: // public static final 类型 常量名 = 值; // Java规范中要求所有的常量的名字全部大写,每个单词之间使用下划线连接 // static final String country = "中国"; public static final String GUO_JI = "中国"; }
package 与 import 使用
/* 关于java语言当中的包机制: 1、包又称为package、java中引入package这种语法机制主要是为了方便程序的管理 不同功能的类被分门别类放到不同的软件包当中,查找比较方便,管理比较方便,易维护。 2、怎么定义package呢? - 在java源程序的第一行上编写package语句。 - package只能编写一个语句 - 语法结构: package 包名; 3、包名的命名规范: 公司域名倒序 + 项目名 + 模块名 + 功能名 采用这种方式重复的几率较低,因为公司域名具有全球唯一性。 例如: com.bjpowernode.oa.user.service org.apache.tomcat.core; 4、包名要求全部小写,包名也是标识符,必须遵守标识符的命名规则 5、一个包将来对应的是一个目录 6、使用了package机制之后,应该怎么编译?怎么运行呢? - 使用了package机制之后,类名不再是Test01了,类名是:com.bjpowernode.docker - 编译:javac java源文件路径(在硬盘上生成一个class文件) - 手动方式创建目录,将Test01.class字节码文件放到指定的目录下 - 运行:java docker.com.bjpowernode.Test01 - 另一种方式(编译 + 运行): * 编译: javac -d 编译之后存放路径 java源文件的路径 * 例如:将F:\Hello.java 文件编译之后放到c:\目录下 javac -d C:\ F:\Hello.java * javac -d . *.java 将当前路径中*。java编译之后存放到当前目录下 * 运行:JVM的类加载器ClassLoader默认从当前路径下加载。 保证DOS命令窗口的路径先切换到com所在的路径,执行: java docker.com.bjpowernode.Test01 */ package docker.com.bjpowernode; public class Test01 { public static void main(String[] args){ System.out.println("Test01's main method execute!"); } }
package docker.com.bjpowernode; public class Test02 { public static void main(String[] args){ // 完整类名是:docker.com.bjpowernode.Test01 docker.com.bjpowernode.Test01 t = new docker.com.bjpowernode.Test01(); System.out.println(t); // docker.com.bjpowernode.Test01@15db9742 // 可以省略包名,因为Test01和Test02在同一个软件包当中。 Test01 tt = new Test01(); System.out.println(tt); // docker.com.bjpowernode.Test01@6d06d69c } }
package docker.com.bjpowernode; import docker.com.bjpowernode.*; // *号导入全部,包名导入文件名 import java.util.*; import java.util.Date; // myeclipse导入类的快捷键:ctrl + shift + o /* import语句用来完成导入其它类,同一个包下的类不需要导入 不在同一个包下需要手动导入 import语法格式 import 类名; import 包名.*; import语句需要编写到package语句之下,class语句之上 */ public class Test03 { public static void main(String[] args){ // 利用import导入包名,省写调用包名 Test01 x =new Test01(); System.out.println(x); //docker.com.bjpowernode.Test01@15db9742 // java.lang.*; 不需要手动引入,系统自动引人 // lang language语言包,是java语言的核心类,不需要手动引入 String s = "abc"; System.out.println(s); // 直接编写以下代码编译错误,因为Date类没有找到 // Date d = new Date(); // java.util.Date d =new java.util.Date(); // 使用import java.util.Date; Date d = new Date(); } } /* 最终结论: 什么时候需要import? * 不是java.lang包下,并且不在同一个包下的时候,需要使用import进行引入 */