本文主要介绍java面向对象理论基础(java面向对象基础知识点),下面一起看看java面向对象理论基础(java面向对象基础知识点)相关资讯。
本文是《零基础学java》栏。它用通俗易懂的文字、图表、代码,带你从零开始走向高薪之路!
本文首发于官方账号【编程攻略】。
在哲学体系中,类和物可以分为主体和客体。在面向对象的编程语言中,所有要面对的事物都可以抽象为对象。在面向对象编程的过程中,我们使用各种对象相互配合来完成我们的程序功能。
在面向对象的语言中,所有使用的对象都有一定的类型,这些类型之间有层次关系,就像生物学中的门、类、目、科、属、种一样。我们可以通过继承机制来实现这种层次关系。
java语言是一种面向对象的语言,所有的对象都可以有一定的属性和一定的行为功能。在java语言中,对象的属性由成员变量(域)描述,行为由方法描述。
类和对象的区别和联系在于,类是抽象的,它拥有类的所有属性和行为,相当于一个模板,而对象是具体的,通过创建相应类的对象来完成相应的功能。我们在做面向对象编程的时候,抽象出类的属性和行为,然后创建具体的对象来完成功能。
date类是在jdk定义的,有一个描述日期的类:java.util.date,表示特定的时刻,精确到毫秒。这里我们定义了一个简单的date类,用年、月和日来表示日期。让 让我们先来看看下面的定义。
公开课日期{ public int year公共int月;公共int日;在这个程序定义中,类被定义为public,年、月、日也被定义为public。它们是什么意思?
我们前面提到了包的概念。我们说过同一个包中的类在功能上是相关的,但是并不是包中的所有这些类都可以被其他包中的类调用。如何区分它们?对于那些可以在包外使用的类,我们在定义时在类名前加public,在定义不能在包外使用的类时不加public。
类体中定义的变量,如年、月、日,称为成员变量(字段),所以成员变量前面的public的作用是表明这些变量是公共的,可以以对象和变量的形式调用,这就叫成员变量的访问权限。例如,如果我们定义了一个日期类型的变量d1,那么我们可以在d1到d1.year中使用年份,在定义成员变量时,除了定义为public,还可以有protected,default(无权限修饰符)和private,它们的限制越来越严格。让 总结一下:
public:public修饰的成员是完全公开的,任何合法的访问形式都可以访问。受保护的成员可以在定义它们的类中访问,也可以由同一个包中的其他类及其子类访问(子类可能不在同一个包中),但不能由其他包中的非子类访问。默认值:不使用权限修饰符。这个类的成员可以在定义它们的类中访问,也可以被同一个包中的其他类访问,但是不能被其他包中的类访问,如果它们不在同一个包中,它们的子类也不能被访问。private:只能在定义它们的类中访问。;这就是全部。在一个类中,我们不仅可以定义成员变量,还可以定义成员方法,成员方法前面也可以有这四种权限控制,意思相同。但是唐 t认为独立类前面可以有private和protected两个修饰符,类前面只能有public或者no,意思上面已经提到了。
关于公共类和源文件的关系,我们之前研究过,这里再提一次:
每个源代码文件中至少定义了一个类。如果有多个类,最多有一个类被定义为public。如果有一个公共类,源代码文件的前缀名应该与该类的类名完全一致。如果没有公共类,源代码文件的前缀名称可能与文件中的任何类都不一致。
测试 ;的日期类已经定义了,我们怎么能测试这个类呢?我们定义了这个类中的main方法了吗?没有main方法的类可以作为java类名在控制台执行吗?显然不是,那我们该怎么办?有两种方案,一种是我们为它定义一个主方法;另一个解决方案是定义另一个类,特别是测试 ;的日期类。让 让我们依次看一看。
添加main方法我们将main方法添加到日期的定义中,代码如下:
公开课日期{ public int year公共int月;公共int日;public static void main(string[]args){ year = 2016;月= 9;day = 5;system . out . println( year : 年份和时间monthe cho 9-@ . com 月份和时间day: 天);}}编译...为什么?又错了?唐 不要惊慌,看看错误消息,这意味着非静态变量可以 不能从静态上下文中引用。这是什么意思?让 让我们看看在main方法前面是否有一个修饰符static。如前所述,任何由static修改的成员变量或方法都可以以类名和成员的形式访问。如果在控制台中以java date的形式执行date类,我想问一下,是不是系统创建一个date对象,然后执行这个对象中的main方法来执行date类?错了,系统直接找到类文件date.class,把这个类调入内存,然后直接执行main。此时内存中没有date对象,这也是为什么main要定义为static的原因,因为main是通过类执行的,而不是通过对象。
上面的解释和这个编译有什么关系?让 让我们看看年、月、日之前是否有修饰语static。不,这意味着不能通过类名直接访问这些成员变量,而必须通过创建类的对象,然后通过对象来访问。当main被执行时,内存中没有对象,所以那些没有静态修饰的成员自然可以 不被访问,因为他们不。;不存在,对吗?你想通了吗?还没有?再想想!
我们可以得出一个结论,我们能记住的只有那些静态修饰的成员(包括成员变量、方法等。)可以在静态修饰方法中使用。如果使用了这个类中的非静态成员,我们还必须创建这个类的对象,并通过对象使用它们。嗯,如果你不 不明白道理,先记住这个结论就好。
根据上述结论,我们再次修改测试电码:
public class date 2 { public int year;公共int月;公共int日;public static void main(string[]args){ date 2 d1 = new date 2;d1.year = 2016年;d1 . month = 9;d1 . day = 5;system . out . println( year : d1 .年份和年份monthe cho 9-@ . com d1 .月与日day: d1.day);}}编译...,好,跑,传球,
在非静态方法中使用静态成员可以吗?我们同意。简单来说,这是因为类先于对象存在,静态成员依赖于类,非静态成员依赖于对象。
在上面的程序中,我们分别给这些成员变量赋值。如果我们不 t给定值直接输出?让 让我们试试:
public class date 3 { public int year;公共int月;公共int日;public static void main(string[]args){ date 3 d1 = new date 3;system . out . println( year : d1 .年份和年份monthe cho 9-@ . com d1 .月与日day: d1 . day);}}编译,运行,结果:,全部0。这里有一个结论:如果一个成员变量没有显式初始化,那么它的初始值为0,或者一个等价于0的值,比如引用变量,没有显式初始化,它的值为null,没有显式初始化的逻辑变量的值为false。这里需要注意的是,我们说的是成员变量。如果它们是局部变量,将在没有显式初始化的情况下使用,编译将失败。例如,上面的代码更改为:
public class date 3 { public int year;公共int月;公共int日;public static void main(string[]args){ date 3 d1;//这里d1是局部变量,system . out . println( year : d1 .年份和年份monthe cho 9-@ . com d1 .月与日day: d1.day)未初始化;}}编译:从编译提示中我们知道d1是在没有初始化的情况下使用的,这是错误的。
创建测试类的代码如下:
//这个类放在date.java文件公共类date { public int year公共int月;公共int日;}//这个类放在testdate.java文件中,公共类test date { public static void main(string[]args){ date。d1 =新日期;d1.year = 2016年;d1 . month = 9;d1 . day = 5;system . out . println( year : d1 .年份和年份monthe cho 9-@ . com d1 .月与日day: d1 . day);}}这两个类都是公共类,所以应该写在两个不同的源代码文件中,分别命名为dat测试完成后会被公开使用,所以我们要把date定义为public,所以源文件的名字是dat测试date类,所以前面的public要去掉。代码如下:
//这些代码放在date.java文件类test date { public static void main(string[]args){ date d1 = newdate;d1.year = 2016年;d1 . month = 9;d1 . day = 5;system . out . println( year : d1 .年份和年份monthe cho 9-@ . com d1 .月与日day: d1 . day);} }公开课日期{ public int year公共int月;公共int日;}这两个类的定义顺序无关紧要。编译完成后,我们可以在命令行上执行:java testdate。
考虑一下这个例子中的封装,有一个问题:在我们创建了日期对象d1之后,我们直接使用d1。该表单为年、月和日赋值。如果我们给它们的值不是合法值呢?例如,month的值不在1和12之间,依此类推。在上面的日期定义中,我们没有办法控制其他代码随意为这些公共修饰变量设置值。
我们可以用私有修饰符来保护这些成员变量。由private修饰的成员只能在类或对象内部访问自身,而不能在外部访问。将上面的日期代码更改为:
普布利c上课日期{私人int年;私人int月;私人int日;}所以我们可以 t通过d1.year访问d1对象中的年份。;t访问年,所以什么 这个变量有什么用?是的,如果没有其他手段,上面的类是没有用的,我们没有办法在里面存储数据。
我们做什么呢我们通过添加一对公共方法来设置和获取每个私有成员变量的值。这些方法的命名方法是:setxxx和getxxx,setter方法给变量赋值,getter取变量的值,布尔型变量用:isxxx命名,xxx是变量的名字,上面的例子改为:
公开课日期{私立int年;私人int月;私人int日;public void setyear(int year){//理论上没有年份0。我们将传入的值为0的实数参数视为1//年。正值表示ad,负值表示bcif(year == 0){//这里有两个年份,一个是成员变量,一个是实参数,是允许的。//为了区分它们,在成员变量year之前加上这个。//不处理参数year如果没有与成员变量同名的变量,可以省略这个。年份= 1;} else { this.year = year} }//因为要取year的值,所以getter方法的返回值与所选变量的类型一致,public int getyear{ return year;} public void set month(int month){ if((month 0)(month 13)){ this . month = month;} else { this . month = 1;} } public int getmonth{返回月份;}public void setday(int day){//这个方法有点复杂,因为我们需要根据year和month的值来判断real参数的值是否符合switch(month){ case 1 echop 9-@ . com case 5 echop 9-@ . com case 7 : case 8 echop 9-@ .com。e10: case 12 : if(day 32 day 0){//在1~31的范围内,this.day = day} else { this . day = 1;//日期超出正常范围,我们设置为1 } breakcase 4 : case 6 : case 9 : case 11 : if(day 31 day 0){//在1~30的范围内,this.day = day} else { this . day = 1;//日期超出正常范围,我们设置为1 } breakcase 2 : if(isleapyear){ if(day 30 day 0){//在1~29的范围内,this.day = day} else { this . day = 1;//超出正常的日期范围,我们设置为1}} else {if (day 29 day 0) {//在1~28的范围内,this.day = day} else { this . day = 1;//日期超出正常范围,我们设置为1 } } breakdefault : this . day = 1;//如果month的值不在上述情况,day设置为1break} }//这个方法判断一年是否是闰年,如果是闰年则返回true,否则返回false//这个方法只在这个类内部使用,所以定义为private private boolean is leap year{//能被400或4整除但不能被100整除的年份为闰年,其他年份为平年如果((year% 400 = = 0) |。= 0))){返回true}返回false//这里能执行,说明是平年}}经过上面的改造,虽然代码长了很多,但是安全了很多。我们不再直接访问年、月和日的值,而是通过相应变量的getter和setter方法。访问时,这些方判断设定值是否符合。
上面的代码其实是可以优化的。例如,setday可以优化如下:
public void setday(int day){//这个方法有点复杂,因为我们需要使用基于year,mon的方法。th的值用来判断自变量的值是否符合this . day = 1;//let ;首先将day设置为1。你不 以下越界情况不需要写代码开关(月)。{ case 1 : case 3 : case 5 : case 7 : case 10 : case 12 e: if(day 32 day 0){//在1 ~ 30。}破;case 4 : case 6 : case 9 : case 11 : if(day 31 day 0){//在1~30的范围内,this.day = day}破;case 2 : if(isleapyear){ if(day 30 day 0){//在1~29的范围内,this.day = day}} else {if (day 29 day 0) {//在1~28范围内,this.day = day} }破;通过上面的例子,我们看到了一个面向对象的概念:封装。我们用私有隐藏数据,用公开访问封装数据,使得数据更加安全可靠。
成员变量的初始化非静态成员变量的初始化在上面的例子中,如果我们创建一个新的date对象,我们可以知道当我们直接取年、月、日的值时,它们的值都是0,这显然是不合理的。为了解决这个问题,我们需要让系统在创建日期对象时自动初始化一个合适的值。为了实现这一目标,我们可以采取三种
在定义成员变量时初始化该值,如上面的代码所示。我们将其修改如下:
public class date { private int year = 1;private int month = 1;private int day = 1;...}上面的代码,这样新date对象的初始值都是1。
第二种是使用构造法。
构造函数是类中的一个特殊方法,它的方法名与类名相同。这个方法没有返回值,甚至是void,构造函数不能作为普通方法对待。每次生成类的对象时,都会调用构造函数。构造函数的作用是在创建对象时初始化它。我们使用构造函数来初始化成员变量,代码如下:
公开课日期{私立int年;私人int月;私人int日;public date{ year = 1;月= 1;day = 1;} ...}上面的代码使我们能够初始化新日期对象中的值。上面的构造方法没有参数。这种构造方法称为默认构造方法。构造函数只能初始化成这个固定值是真的吗?当你创建一个对象时,你能指定初始化值吗?答案是肯定的,就是使用带参数的构造函数。代码如下:
公开课日期{私立int年;私人int月;私人int日;public date (int year,int month,int day){//下面的代码使用setter方法进行初始化,因为setter方法提供了参数检查。//如果不使用setter方法,我们需要重写参数校验码setyear(year);setmonth(月);setday(日);} ...}上面的代码使我们能够在创建新的date对象时指定一个初始化值,比如:date d = new date(2016 . 9 . 5);。然而,上面的代码没有定义无参数的构造函数,所以我们可以 t使用无参数构造函数创建日期对象,如:date d = new date;编译时会出现如图所示的错误:为什么?这是因为如果在定义类的时候没有定义构造函数,编译器会自动创建一个没有参数的空公共构造函数作为该类的构造函数。但是只要定义了构造方法,不管有没有参数,编译器都不再自动生成,会出现上面的。
此外,jvm将忽略构造函数中生成的异常,即使在构造函数中使用了try。
public class test { public test{ try { system . out . println( 试图抛出一个异常);双x = 1.0/0.0;//这句话会生成一个exception} catch(exception e)除以0。{ system . out . println( 捕获到异常 );}最后{ system . out . println( 里面终于 );} }公共静态void main(string args[]){ test test = new test;上面的代码执行后的结果如下:从图中可以看到,发生的异常没有被捕获。
第三种方法是使用实例语句块。那么什么是实例语句块呢?实例语句块是由一对可以执行的大括号括起来的一系列语句。该语句块在类内部,但不在任何方法内部,如下面的代码所示:
公开课日期{私立int年;私人int月;私人int日;//下面的大括号是示例语句块{ year = 1;月= 1;day = 1;} ...}上面的示例语句块将在执行构造函数之前执行。如果出现多个实例语句块,请按顺序执行它们。
如果同时采用这三种方法呢?代码如下:
public class date { private int year = 1;private int month = 1;private int day = 1;{ year = 2;月= 2;日= 2;} public date{ year = 3;月= 3;日= 3;如果你想为上面的日期类创建一个新的对象,它的初始值是1,2还是3?在创建对象时,它会在堆中为对象分配存储空间,然后将分配空间的所有内容设置为默认初始值0,然后用定义成员变量时的值初始化成员变量,然后执行实例语句块,最后执行构造方法。因此,上述示例的初始最终值为3。
静态成员变量的初始化我们前面提到的是非静态成员变量的初始化。我们知道有一类成员变量是用静态修饰的,这类成员变量是独立于对象的。那么如何初始化这类变量呢?首先要明确一点,静态成员变量的存储空间与该类的任何对象都没有关联,它们的存储空间是独立的。由此,我们可以得出两个结论。首先,静态成员变量的值只能初始化一次。其次,静态成员变量的值不能在构造函数中初始化(因为创建对象时会调用构造函数)。那么如何初始化一个静态成员变量呢?有两种方法:
就像初始化非静态成员变量一样,直接把初始化赋给静态成员变量。值,如:public class test { public static int first = 1;public static int second = 2;}二、使用静态语句块,如下:public class test { public static int first;public static int秒;//下面的语句是静态语句块,不能放在方法体static { first = 1;秒= 2;}}在一个类中,可以出现多个静态语句块,这些语句块按顺序执行。
静态成员变量的初始化发生在第一次使用该成员变量时,然后该成员变量将不会被重复初始化。而且类中静态成员变量的初始化发生在非静态成员变量初始化之前,所以下面这段代码不合适:public class test { public int first = 1;公共静态int second = first类定义java中的成员可以包含类中的两种成员:实例成员和类成员。
实例成员实例成员(包括实例成员变量和实例方法)属于对象,通过引用访问:引用变量,实例成员名称;定义类时,如果成员没有被static修改,那么定义的成员就是实例成员,比如:int i = 10void f{…}实例成员的存储分配通常,类只是描述,存储空间是通过使用new分配给对象的。未被static修改的成员是对象的一部分,因此此类实例成员的存储分配与对象的分配一起分配。比如:类t { int i;void f{}} .。。t t1,t2;t1 =新t;t2 =新t;那么这个时候我有两个副本,一个在t1,一个在t2。类成员(包括类成员变量和类方法)通过t1.i和t2.i属于类,可以通过类名或引用访问:类名。类成员名称;定义类时,如果成员被static修改,那么定义的成员就是类成员,比如:static int count = 0;static之前的public static void main(string args[]){…}类成员的存储分配用于成员变量,无论有多少个对象,成员变量只保留一个公共存储,称为类变量(static variables);如果你用静态来修饰一个方法,这个方法叫做类方法(静态方法),那么当你调用静态方法的时候,方法不依赖于具体的对象,也就是你可以调用一个方法。而不创建对象。对于类成员的使用,可以使用类名,也可以通过引用使用,比如:class t { static int i = 47静态void f{ i;}}。。。t t1,t2;t1 =新t;t2 =新t;此时i只有一个副本,被t1.i和t2.i使用,也可以被t.i引用,其值都是47。在t.i .的实施中;t1.i和t2.i的值都是48;对f的调用可以以t1.f的形式进行;也可以用t . f;使用方法。根据java编程规范,我们建议只对静态成员使用类名引用。类成员和实例成员总结当你使用static时,意味着这个成员变量或方法不依赖于这个类的任何对象,所以你可以使用这个静态数据或方法,而不需要创建对象。对于非静态数据和方法,您必须创建一个对象,然后使用它来操作非静态数据和方法。因此,因为静态方法不需要创建对象,所以静态方法不能直接访问非静态成员。非静态方法可以直接调用静态成员公共类test { static int i = 0;int j = 10静态void f{ i;} void s{ f;j;} public static void main(string[]args){ test t = new test;t . s;system . out . println(i);}}static的一个重要应用就是调用方法而不创建对象。比如在定义类的时候,main将personality定义为非static,将generality定义为staticthis。在java中,我们经常会看到这个关键字的使用。它用于两种场合:
这是作为引用来引用自己的,每个对象都有一个this。在类的成员方法中,这用于指示该对象中方法或变量的使用。如果不会引起歧义,可以省略。例如,在上面的一系列setter方法中,因为参数与成员变量同名,为了表示区别,这个成员变量之前不能省略。
这不能在静态方法中使用。因为静态方法的执行根本不需要java对象的存在,而是通过使用类名直接访问。方法,这表示当前对象,因此这根本不能用于静态方法。
这可以用在构造函数中,以及这个类中的其他构造函数中到
语法:this([argument]);函数:在一个构造函数中调用另一个构造函数。目的:代码重用。this (argument):它必须是构造函数中执行的第一条语句,并且只能调用一次。让 让我们阅读下面的代码。
公共类flower { int petal count = 0;string s =新字符串( 零 );flower(int petals){ petal count = petals;system . out . println( 只有int arg的构造函数,petalcount = petal count);} flower(string ss){ system . out . println( 只有字符串参数的构造函数,s = ss);s = ss}flower(string s,int petals){ this(petals);//调用flower(花瓣),但是不能写flower(花瓣)//!这(些);//can ;不要叫两个!this.s = s//这是使用这个系统的另一种。out . println( 字符串标记和);} flower{ this( 嗨 , 47);system . out . println( 默认构造函数(无参数));}void print {//!这(11);//不在非构造函数内部!system . out . println( petalcount = petalcount s = s);} public static void main(string[]args){ flower x = new flower;x . print;} }///: ~私有构造函数也可以有public之类的修饰符,在构造方法之前限制构造函数的访问权限。通常,如果类是公共的,构造函数也是公共的,因此可以通过new调用它。那么,如果构造函数前面用private修饰会怎么样呢?我们可以 不要在类外生成该类的对象。可以自己echo1-@q。q.com,请。
这是否意味着私人可以 不能用在构造函数的前面?当然,这是一个非常有用的情况。在某些情况下,某些类在系统中只能有该类的一个实例(对象)。这时,我们可以将这个类的构造函数定义为private。示例代码如下:
public class handler {//handler变量用来保存这个类对象的引用;私有静态handlerhandler = nullprivate handler{/* set something here */}/该类的对象只能通过gethandler方法从私有变量handler中获取公共静态gethandler(/* arglist */){//如果handler的值不为空,则说明该类的对象在系统中已经存在,可以直接取出,不会再生成,这样就保证了singleton if(!handler)handler = new handler;返回处理程序;} public static void main(string args[]){ handler . gethandler;}}最后一篇文章来自官方账号【编程攻略】。更多java学习资料见【编程攻略】。
标签:
可变成员
了解更多java面向对象理论基础(java面向对象基础知识点)相关内容请关注本站点。