类和对象(1)
1.面向对象的编程
面向对象的三大特征:
(1)封装:即把客观的事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类和对象对其进行操作;对不可信的类进行信息的隐藏。(内部操作对外部不可见)
(2)继承:一种能力。可使用所有现有类的所有功能,且无需进行重新编写对功能进行扩展。
(3)多态:值一个类实例的相同方法在不同情形下的不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的接口。
面向过程编程缺少了代码的可重用性设计。
名词拓展:
OO:面向对象 | OOA:面向对象分析 |
OOD:面向对象设计 | OOP:面向对象编程 |
2.类与对象的定义与使用
(1)类与对象
类:共性的概念;而对象指的是一个具体的,可使用的事物。先产生类,后有对象,对象的行为,一定在类中进行了定义。
类的组成:方法(操作行为)
属性(变量;描述每个对象的具体特点)
类的语法:
class 类名{
属性1;
属性2;
……
属性n;
方法1(){ }
……
}
注:此时的方法不再由主类调用,而由对象直接调用。
生成对象的语法;
类名 对象名 = new 类名();
定义person类 class Person1{ Public String name; private int age; public Person1(String name,int age){ this.name = name; this.age = age; } public String myPrint(){ return "name= "+this.name+",age= "+this.age; } } |
生成类的实例化对象: Person1 per = new Person1("张三",20); |
调用实例变量与实例方法: System.out.println(per.name);//调用成员变量 System.out.println(per.myPrint());//调用成员方法 |
(2)对象内存分析
只要出现了new就分配了内存,java中所谓的性能调优即调整内存问题,如下进行对象的内存分析。
//对象的内存分析 class Person2{ String name; int age; public Person2(){ //构造方法 } } public class Test8{ public static void main(String[] args){ Person2 per = new Person2(); per.name = "lemon"; per.age = 18; System.out.println("name= "+per.name+",age= "+per.age); } } |
运行结果: name= lemon,age= 18 |
对象(引用数据类型)必须在实例化以后才可调用,否则会抛出NullPointerExcertion异常(运行时错误)。且只有引用数据类型(数组、类、接口)才可产生此类异常。
3.private实现封装处理
封装是面向对象中最复杂的概念,使用private关键字对封装进行处理只是第一步。
private实现对类中属性的封装(要想在主方法中获取到该属性的值,必须在private属性所在的类中提供setter和getter方法)。如下例:
setter方法:主要用于进行属性内容的设置与修改
getter方法:主要用于属性内容的取得
class Man{ //使用private封装属性 private String name;//私有属性 private int age;//私有属性 public void setName(String n){ name = n; } public String getName(){ return name; }
public void setAge(int a){ if(a>=1 && a<=180){ age =a; }else{ age = 0; } } public int getAge(){ return age; } public void myPrint(){ System.out.println("name= " + name + ",age= " +age); } } public class Test8{ public static void main(String[] args){ Man per1 = new Man(); per1.setName("张三"); per1.setAge(18); per1.myPrint(); } } |
运行结果: name= 张三,age= 18 |
4.构造方法与匿名对象
1.产生对象的方法:
类名称 方法名称 = new 类名称( )
针对以上定义作如下分析:
2.构造方法:
使用关键字new实例化对象来进行调用的方法。应遵循如下规则:
(1)方法名称必须与类名相同。
(2)构造方法没有返回值类型。
(3)每一个类中至少存在一种构造方法,如若没有明确定义,则系统会给出一个默认的无参构造方法。(若类中定义了构造方法,则默认的无参构造方法不再生成)
构造方法无返回值,为什么没有void声明?
现在类中的组成:属性、构造方法、普通方法
1. 属性是在对象开辟堆内存时开辟的空间
2. 构造方法是在使用new后调用的
3. 普通方法是在空间开辟了、构造方法执行之后可以多次调用的。
public void Person(){ } //命名不标准的普通方法
public Person() { ] //构造方法
所以编译器是根据程序结构来区分普通方法和构造方法的,所以在构造方法前没有返回值类型声明。
构造方法的调用和内存分配基本是同时完成的,所以可以使用构造方法对类中的属性进行初始化操作,可避免多次的setter和getter方法调用。如下例:
//构造方法 class Man{ private String name; private int age; public Man(String n,int i){ name = n; age = i; } public void myPrint(){ System.out.println("name= "+name+",age="+age); } } public class Test8{ public static void main(String[] args){ Man per = new Man("lemon",18); per.myPrint(); } } |
运行结果: name= lemon,age=18 |
3.构造方法的重载
参数的类型或个数不同(若干构造方法时按照参数的个数升序或降序)
//构造方法的重载 class Man{ private String name; private int age; public Man(){ System.out.println("我是无参构造方法"); } public Man(String s){ System.out.println("我是带一个参数的构造方法"); } public Man(String n,int i){ name = n; age = i; } public void myPrint(){ System.out.println("name= "+name+",age="+age); } } public class Test8{ public static void main(String[] args){ Man per1 =new Man(); Man per2 =new Man("lemon"); Man per = new Man("lemon",18); per.myPrint(); } } |
运行结果: 我是无参构造方法 我是带一个参数的构造方法 name= lemon,age=18 |
一般定义类时:①定义属性->②定义构造方法->③定义普通方法
4.匿名对象: new Man("lemon",18).myPrint();
5.this 关键字
//this关键字 class Man{ private String name; private int age; public Man(String name,int age){ name = name; age = age; } public void myPrint(){ System.out.println("name= "+name+",age="+age); } } public class Test8{ public static void main(String[] args){ Man per = new Man("lemon",18); per.myPrint(); } } |
运行结果: name= null,age=0 |
this 关键字的用途:(只要在类中方法访问类中属性一定要加关键字this)
(1)调用本类属性;
(2)调用本类方法;
(3)表示的当前方法
(1)this调用本类属性
有上述例子可以看出当构造方法中参数与类中属性同名的时候,则无法对其进行正确的赋值。在此时我们就可以使用this关键字便可以正确的给对象的属性赋值。即
//this调用本类属性 class Man{ private String name; private int age; public Man(String name,int age){ this.name = name; this.age = age; } public void myPrint(){ System.out.println("name= "+name+",age="+age); } } public class Test8{ public static void main(String[] args){ Man per = new Man("lemon",18); per.myPrint(); } } |
运行结果: name= lemon,age=18 |
(2)this调用本类方法
调用普通方法:this.方法名(参数)
不需加this也可以直接调用,加上this以区分方法的定义来源。
调用构造方法:this(参数)
支持构造方法的互相调用,但应注意:this调用构造方法时必须放在构造方法首行;使用this调用构造方法时要留有出口。
class Man{ private String name; private int age; public Man(){ System.out.println("*********调用构造方法*********"); } public Man(String name){ this();//调用无参构造方法 this.name = name; } public Man(String name,int age){ this(name);//调用带一个参数的构造方法 this.age = age; this.myPrint();//调用本类的普通方法 } public void myPrint(){ System.out.println("*********调用普通方法*********"); } public void printInfo(){ System.out.println("name= "+name+",age="+age); } } public class Test8{ public static void main(String[] args){ Man per = new Man("lemon",18); per.printInfo(); } } |
运行结果: *********调用构造方法********* *********调用普通方法********* name= lemon,age=18 |
(3)this表示当前对象
只要this调用了本类的方法,this就表示当前正在执行的对象。
//this表示当前对象 //只要对象调用了本类的方法,this就表示当前正在执行的对象 class Man{ private String name; private int age; public void myPrint(){ System.out.println("当前对象: "+this); } } public class Test8{ public static void main(String[] args){ Man man1 = new Man(); System.out.println("主方法 "+ man1); man1.myPrint(); System.out.println("******************"); Man man2 = new Man(); System.out.println("主方法:"+man2); man2.myPrint(); } } |
运行结果: 主方法 test.Man@6d06d69c 当前对象: test.Man@6d06d69c ****************** 主方法:test.Man@7852e922 当前对象: test.Man@7852e922 |
6.static关键字
static可以修饰属性和方法
(1)static属性(类属性)
实例变量(传统属性)(保存在堆空间中,且每个对象独享属性)
class Man{ String country = "China"; String name; int age; public void myPrint(){ System.out.println("name= "+this.name+",age= " +this.age+",country= "+country); } } public class Test8{ public static void main(String[] args){ Man man1 = new Man(); Man man2 = new Man(); man1.name = "demon"; man2.name = "lemon"; man1.age = 16; man2.age = 18; man1.myPrint(); System.out.println("***********************************"); man2.myPrint(); } } |
运行结果: name= demon,age= 16,country= China *********************************** name= lemon,age= 18,country= China |
实例变量(传统属性)的内存分析:
共享属性(保存在全局数据区的内存中,所有对象都可以对该区域进行访问)
若对country属性加上static属性,则使其成为共享属性。
修改上述代码:static String country = "China";
则内存分析图如下:
注意:
使用static 属性(类属性),应使用类名称.属性名来访问。
所有的非static属性(类属性)必须在对象实例化后才可使用,而static(类属性)可以在对象未初始化的时候使用。
在此时若修改(static String country = “China”)的值,所有的对象都同步的得到修改。
定义类时如何选择实例变量和类属性?
99%的情况下不会考虑static属性,而使用非static属性。
如果要描述共享属性,或者不受对象实例化的影响可以使用static属性。
(2)static方法(类方法)
所有的static方法不允许调用非static定义的方法或者属性。
所有的非static方法允许访问static的属性或方法。
使用static方法的目的: 某些方法不想受到类的控制,即没有实例化对象就可以执行。
//static方法 class Man{ private static String country = "China"; private String name; private int age; public Man(String name,int age){ this.name = name; this.age =age; } public static void setCountry(String C){ country = C; } public void myPrint(){ System.out.println("name= "+this.name+",age= " +this.age+",country= "+country); } } public class Test8{ public static void main(String[] args){ Man.setCountry("China"); Man man = new Man("demon",26); man.myPrint(); } } |
运行结果: name= demon,age= 26,country= China |