9.30上课问题的整理与思考
上周五的java课上,王建民老师主要围绕类与对象展开他的讲解,主要是以下内容:
1.编写类的模板
类的模板:
public/private class 类名
{ public/private 数据类型 变量名;
public/private 数据类型 方法名(参数列表){ }
}
public :访问与存取不受限制
private :除非是属于类自己的方法,其它对象不能访问与存取
class MyClass { // 公有字段 public String Information = ""; // 自定义公有Java实例方法 public void myMethod(String argu) { System.out.println(argu); } // 定义属性:私有字段+get方法+set方法 private int value; public int getValue() { return value; } public void setValue(int value) { this.value = value; } }
在Java中,可以通过组合一私有字段和一对get/set方法来定义一个属性。
对类的应用:
package practice; public class ClassAndObjectTest { public static void main(String[] args) { //创建类的实例,定义一个对象变量引用这一实例 MyClass obj = new MyClass(); //通过对象变量调用类的公有方法 obj.myMethod("Hello"); //给属性赋值 obj.setValue(100); //输出属性的当前值 System.out.println(obj.getValue()); //直接访问对象公有字段 obj.Information = "Information"; //输出对象公有字段的当前值 System.out.println(obj.Information); } }
二、一种新的变量形式
原始数据类型:int float之类的变量,int a=100;
引用类型:引用一个对象的变量称为“引用类型”的变量,形如
MyClass obj = new MyClass();
三、变量与内存分配
声明一个对象类型的变量时,实际上并没有创建一个对象,此变量为null:MyClass obj = new MyClass() obj------null
定义一个原始类型的变量时,会马上给其分配内存:int a=100 a-----100
null:代表一个对象变量不引用任何对象
独特的对象引用:this
对象中所有数据字段都是通过this指针间接引用的
作为常量的对象变量
用final定义一个“常量”对象变量
final MyClass obj=new MyClass()
“常量”对象变量不能指向另一个对象,但可以修改对象,比如设置它所引用对象的某个公有字段值
四、对象判等
对于原始数类型的变量可以直接用“==”来判断是否一样
对象变量是否可以用“==”来判断呢?
public class ObjectEquals { public static void main(String[] args) { MyTestClass obj1=new MyTestClass(100); MyTestClass obj2=new MyTestClass(100); System.out.println(obj1==obj2);//false System.out.println(obj1.equals(obj2));//true } }
通过代码可以发现,对象变量不能通过“==”来直接判断是否相等,能通过equals函数来判断。
原因如下
当“==”施加于原始数据类型变量时,是比较变量所保存的数据是否相等
当“==”施加于引用类型变量时,是比较这两个变量是否引用同一对象。
引用代表地址,所以“==”实际上相当于比较两个引用类型变量中保存的对象地址是否相同。
五、动手动脑
以下代码为何无法通过编译?
public class Test { public static void main(String [] args){ Foo obj1=new Foo(); } } class Foo{ int value; public Foo(int initValue){ value=initValue; } }
通过编译发现该代码无法运行,查找发现类里面提供了有参构造方法,系统没有提供默认构造方法,无法被调用
结论:
当类里面没有构造方法时,系统自己提供一个默认构造方法
当类里面有了自定义的构造方法时,系统不会再提供默认构造方法,如果需要无参构造方法,需要自己定义。
六、类的初始化块
类的初始化块:在类中使用{和}将语句包围起来,直接将其作为类的成员
public class InitializeBlockDemo { /** * @param args */ public static void main(String[] args) { InitializeBlockClass obj=new InitializeBlockClass(); System.out.println(obj.field); obj=new InitializeBlockClass(300); System.out.println(obj.field); } } class InitializeBlockClass{ //下面这句在初始化块之前与之后,会影响到field字段的初始值 //public int field=100; { field=200; } public int field=100; public InitializeBlockClass(int value){ this.field=value; } public InitializeBlockClass(){ } }
通过运行以上代码,结果为
100
300
通过该结果可以看出 java字段初始化的规律为
在使用默认构造方法时,初始化块和public定义的变量,两个都调用,谁在后面就初始化为谁
类的初始化块不接受任何参数,一旦被调用就会执行,用于封装一些必须被执行的代码
七、静态初始化块
动手动脑
静态即加一个static关键字
package practice; class Root { static { System.out.println("Root的静态初始化块"); } { System.out.println("Root的普通初始化块"); } public Root() { System.out.println("Root的无参数的构造器"); } } class Mid extends Root { static { System.out.println("Mid的静态初始化块"); } { System.out.println("Mid的普通初始化块"); } public Mid() { System.out.println("Mid的无参数的构造器"); } public Mid(String msg) { //通过this调用同一类中重载的构造器 this(); System.out.println("Mid的带参数构造器,其参数值:" + msg); } } class Leaf extends Mid { static { System.out.println("Leaf的静态初始化块"); } { System.out.println("Leaf的普通初始化块"); } public Leaf() { //通过super调用父类中有一个字符串参数的构造器 super("Java初始化顺序演示"); System.out.println("执行Leaf的构造器"); } } public class TestStaticInitializeBlock { public static void main(String[] args) { new Leaf(); } }
通过运行可以知道:
- 静态初始化块只执行一次。
- 创建子类型的对象时,也会导致父类型的静态初始化块的执行。
八、一个有趣的问题:如何在静态方法中访问类的实例成员
public class Test { int x = 3;//类的实例变量,初始化值为3 static int y = 4;//类的静态变量,初始化值为4 public static void method()//静态方法 { System.out.println("实例变量x = " + new Test().x);//在静态方法中访问类的实例变量需首先进行类的实例化 System.out.println("静态变量y = " + y);//在静态方法中可直接访问类的静态变量 } public static void main(String[] args) { Test.method(); Test ex = new Test(); System.out.println("x = " + ex.x); } }
在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。
静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制。