Java面向对象(上)_2关键字()是java提供的一个关键字,它是直接父类对象的默认引用staticsuperfi-程序员宅基地

技术标签: super  Java基础  继承  this  构造函数  多态  

这几天在家看了一些关于java面向对象基础的书籍,于是总结一下自己学到的东西。

一:类,对象,属性,方法,构造器的概念:

类:用于描述客观世界里某一类对象的共同特征。

对象:可以看成是静态特殊(属性)和动态特征(方法)的封装体(简单的理解:类可以看成对象的模版,对象可以看成类的具体实例)。

属性:用于定义类或类的实例所包含的数据。

方法:定义类或类的实例的行为特征或功能实现。

构造器:构造器是一个特殊的方法,主要用于创建类的实例。java语言中器是创建对象的重要途径。


二:this和super关键字

this关键字:是一个对象的默认引用,this总是指向调用该方法的对象。

super关键字:super是直接父类对象的默认引用 。

this作为对象的默认引用有一下两种情况:

1:构造函数中引用该构造函数执行初始化的对象。

2:在方法中引用调用该方法的对象。

this关键字最大的作用就是让类中一个方法,访问该类的另一个方法或属性。

this可以代表任何对象,当this出现在某个方法体中时,它所代表的对象是不确定的,但它的类型是确定的,它所代表的对象只能是当前类;只是当这个方法被调用时,它所代表的对象才能确定下来:谁在调用这个方法,this就代表谁。

如果在static修饰的方法中使用this关键字,则这个关键字就无法指向合适的对象。所以,static修饰的方法中不能使用this引用。由于static修饰的方法不能使用this应用。所以static修饰的方法不能访问不使用static修饰的普通成员。

如果需要在子类方法中调用父类被覆盖的实例方法,可使用super关键字作为调用者来调用父类被覆盖的实例方法。

super也不能出现在static修饰的方法中,static修饰的方法是属于类的,该方法的调用者可能是一个类,而不是对象,也就不存在对应的父类对象了,因而super引用也就失去了意义。

特别注意:Java程序创建某个类的对象时,系统会隐式创建该类父类的对象。只要有一个子类对象存在,则一定存在一个与之对应的父类对象。在子类方法中使用super引用时,super总是指向作为该方法调用者的子类对象所对应的父类对象。这就和this很类似。this总是指向调用该方法的对象。而super则指向this指向对象的父对象。


三:深入构造器:

构造器是一个特殊的方法,该方法主要用于创建类的实例,Java语言里构造器是创建对象的重要途径。因此,Java类必须包含一个或一个以上的构造器。   同一个类里具有多个构造器,多个构造器的形参列表不同,这就叫构造器的重载。

构造器最大的用处就是在创建对象时执行初始化操作。

如果程序员没有为Java类提供任何构造器,则系统会为这个类提供一个无参数的构造器,这个构造器的执行体为空,不做任何事情,无论如果,Java类至少包含一个构造函数。一旦程序员提供了自定义的构造器,则系统不再提供默认的无参数构造器。如果希望该类保留无参数的构造器,此时就需要程序员自己提供。

注意:构造器是创建Java对象的重要途径,通过new关键字调用构造器时,构造器也确实返回了该类的对象,但这个对象并不是完全由构造器负责创建的。实际上 ,当程序员调用构造器时,系统会先为该对象分配内存空间,并为这个对象执行默认的初始化,这个对象已经产生了,这些操作都是在构造器执行之前就完成了。也就是说,当系统开始执行构造器的执行体之前,系统已经创建了一个对象,只是这个对象还不能被外部程序访问,只能在该构造器中通过this来引用它。当执行构造器的执行体执行结束后,这个对象作为构造器的返回值被返回,通常还会赋给另外一个引用类型的变量,从而让外部程序可以访问该对象。       

使用this调用另外一个重载的构造器值能在构造器中使用,而且必须作为构造器执行体的第一条语句。使用this调用重载的构造器时,系统会根据this后括号里的实参来调用形参列表与之对应的构造器。

构造器是否有返回值?

解答:实际上,类的构造器是有返回值的,当我们用new关键字来调用构造器时,构造器是返回该类的实例,可以说这个类的实例就是构造器的返回值,因为构造器的返回值类型总是当前类。因此无须定义返回值类型。但必须注意不能在构造器中显示使用ruturn来返回当前类的对象,因为构造器的返回值是隐式的。

四:类的封装,继承,多态:

封装:封装保证软件部件具有优良的模块性的基础封装的目标就是要实现软件部件的“高内聚、低耦合”,防止程序相互依赖性而带来的变动影响。在面向对象的编程语言中,对象是封装的最基本单位面向对象的封装比传统语言的封装更为清晰、更为有力。简单的理解就是,将类中的数据都隐藏起来,只是提供一个接口,让外部通过提供的接口进行访问类中的数据。

继承:在java中使用extends关键字来实现类的继承。实现继承的类叫做子类,被继承的类叫做父类,基类或者叫超类。

Java只支持单继承,不允许多继承。一个子类只能有一个直接的父类,一个父类可以派生出多个子类。当子类继承了父类,则子类将获得父类的全部属性(privarte属性除外)和方法。

子类重写父类的方法时:必须和父类方法具有相同的名字,参数列表和返回值类型,访问权限必须高于或等于父类的访问权限(方法访问修饰符)。

 多态:同一类型的引用调用同一方法但效果不同。

构成多态的条件:1.要有继承,2.要有重写,3.父类应用指向子类对象。

注意:Java引用变量有两个类型,一个是编译时的类型,一个是运行时的类型,编译时的类型是由声明该类变量时使用的类型决定,运行时的类型是由实际赋给该变量的对象决定。如果编译时类型和运行时类型不一致,就会出现所谓的多态。

精典实例:

public class Test1 extends BaseClass{
	 public int book=10;
	 public void test(){
		 System.out.println("重写父类的方法");
	 }
	 public void sub(){
		 System.out.println("子类的普通方法");
	 }
	 public static void main(String[] args) {
		//编译时类型和运行时类型不一致
		BaseClass base=new Test1();
		//将打印父类的6
		System.out.println("book="+base.book);
		base.base();
		//打印子类重写父类的方法内容
		base.test();
	}
}
class BaseClass{
	public int book=6;
	public void base(){
		System.out.println("我是父类的普通方法");
	}
	public void test(){
		System.out.println("将被子类重新的方法");
	}
}
打印结果:book=6
    我是父类的普通方法
    重写父类的方法

解析:引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法。所以BaseClass base=new Test1();代码中BaseClass是编译时类型,Test1是运行时类型。编译时只能调用BaseClass类的方法,而不能调用Test1类中的方法。而在运行时,调用的是Test1类中的方法,所以当执行base.test();这句代码时,打印的是子类重写父类的方法内容。System.out.println("book="+base.book);执行这句代码时,为什么会打印父类的值呢? 属性与方法就不同了,对象的属性是不具备多态性。通过引用变量来访问其包含的实例属性时,系统总是试图访问它编译时类所定义的属性,而不是它运行时类所定义的属性。


 五:方法的重载和重写:

方法重载:Java允许同一个类中定义多个同名的方法,如果同一个类中包含两个或两个以上方法的方法名相同,但形参列表不同,这就叫方法的重载。

重载的要求:同一类中方法名相同,参数列表不同。方法的返回值,修饰等等与方法重载没有关系。

方法重写:子类包含父类同名方法的现象叫方法的重写。

重写的要求:子类重写父类的方法时,必须和父类方法具有相同的方法名字,参数列表和返回值类型,子类重写父类的方法时,访问权限必须高于或等于父类的访问权限(方法访问修饰符)。

注意:如果被重载的方法中包含了长度可变的形参。比如同一类中包含test(int a)和test(int...nums),当执行对象.test(2)方法时,将会执行test(int a)方法。


六:成员变量和局部变量:

Java语言中,根据定义变量的位置不同,将变量分为了两类:成员变量和局部变量。

成员变量:是指在类范围里定义的变量,也就是常说的属性。

局部变量:是指在一个方法内定义的变量。


成员变量:

成员变量分为类属性和实例属性两种,定义一个属性时不使用static修饰的就是实例属性,反之则是类属性。其中类属性从这个类的准备阶段开始存在,直到系统完全销毁这个类,类属性的作用域 与这个类的生存范围相同;而实例属性则从创建实例开始存在,直到系统完全销毁这个实例,实例属性的作用域与对应实例的生存范围相同。简单的说实例属性随实例的存在而存在,而类属性则随类的存在而存在。

局部变量:

形参:在定义方法时在括号中定义的变量,形参的作用域在整个方法内有效。

方法局部变量:在方法体内定义的局部变量,它的作用域是从定义该变量时生效,到该方法结束是失效。

代码块局部变量:在代码块中定义的局部变量,这个局部变量的作用域从定义该变量时生效,代码块结束时失效。

注意:局部变量除了形参之外,都必须显示初始化。

Java允许局部变量和成员变量同名,如果方法里的局部变量和成员变量同名,局部变量会覆盖成员变量,如果需要在这个方法里引用被覆盖的成员变量,则可以使用this(实例属性)或类名(类属性)作为调用者来访问成员变量。

成员变量和局部变量的初始化和在内存中的运行机制:

1:成员变量

当系统加载类或创建该类实例时,系统自动为成员变量分配内存空间,并自动为成员变量指定初始值。

成员变量的使用情况:

(1)如果需要定义的变量是用于描述某个类或者某个对象的固有信息,比如人的身高,体重等建议使用实例变量。如果这种信息对这个类的所有实例完全相同,比如人的眼睛,所有人的眼睛都是两个,像这样的属性建议定义为类属性。

(2)如果需要定义一个变量用于保存该类或者实例运行时的状态信息,则建议使用成员变量。

(3)如果某个信息需要某个类的方法之间进行共享,建议使用成员变量。

2:局部变量

局部变量定义后,必须显示的初始化。系统不会为局部变量执行初始化。这说明定义局部变量后,系统并没有为这个变量分配内存空间,只有当程序为这个局部变量赋初始值时,系统才会为该变量分配内存空间,并将初始化值保存到内存中。

局部变量总是保存在方法的栈内存中,栈内存中的变量无须系统垃圾回收,栈内存中的变量往往是随方法或代码块的运行结束而结束的。

七:方法参数传递机制:

形参:定义方法时,方法名后的括号中的参数。

实参:调用方法时实际传入的参数。

问题:Java的实参值是怎么传入方法的呢?

解答:这是由Java方法的参数传递机制来控制的,Java里方法的参数传递方式只有一种:值传递。所谓值传递,就是将实际参数值的副本(复制品)传入方法内,而参数本事不会受到任何影响。【Java里的参数传递类似与《西游记》里的孙悟空,孙悟空复制了一个假孙悟空,这个假孙悟空具有和孙悟空同样的能力,可以降妖除魔。但不管这个假孙悟空遇到什么事,真孙悟空不会受到任何影响。呵呵这里打了一个简单的比方】

简单实例:

public static void main(String[] args) {
		//定义两个整型变量并初始化	
		int a=5,b=10;
		//调用交换变量值的方法
		swap(a, b);
		//打印变量a和变量b的值
		System.out.println(" 交换后,实参a="+a+"   ,b="+b);
	}
	/**
	 * 交换两个整型变量的值
	 * @param a 
	 * @param b
	 */
	private static void swap(int a,int b){
		//定义一个临时变量,用来存放a变量的值
		int temp=a;
		//把b赋值给a
		a=b;
		//把temp的值赋值给b
		b=temp;
		System.out.println("swap方法中的a="+a+"  ,b="+b);
	}

控制台打印的结果是:

swap方法中的a=10  ,b=5
交换后,实参a=5   ,b=10

解析:当程序执行main方法中的swap()方法时,系统进入swap方法,并将mian方法中的变量a和变量b作为参数值传入swap方法,此时传入swap方法的是a,b变量的副本,而不a,b变量的本身。进入swap方法后,开始执行变量值的交换工作。执行完swap方法体后,实质只是交换了副本的值,并没有交换a,b变量本身。  从内存的角度分析该程序:在main方法中调用swap方法时,main方法还为结束。因此,系统分别为main方法和swap方法分配两块栈区,分别用于保存mian方法和swap方法的局部变量。main方法中的a,b变量作为参数传入swap方法,实际上是在swap方法栈区中重新生产了两个变量a、b,并将main方法栈区中a、b变量的值分别赋给swap方法栈区中的a、b参数。此时,系统存在两个a变量,两个b变量。只是存在于不同的方法栈区中。所以对swap中的变量a和变量b进行任何操作,对main方法中的a、b变量没有任何影响。

Java对于引用类型的参数传递,一样采用的是值传递方法。这样说或许很多人都会对引用类型的参数传递产生误解。

引用类型的参数传递实例:

public class TestRefenceTransfer {
	
	public static void main(String[] args) {
		//创建Person对象
		Person person=new Person();
		//给Person对象赋值
		person.age=23;
		person.weight=50;
		//调用交换值方法
		swap(person);
		//打印输出
		System.out.println(" 交换后,age="+person.age+"  ,weight="+person.weight);
	}
	/**
	 * 交换对象的值
	 * @param person 
	 */
	private static void swap(Person person){
		int temp=person.age;
		person.age=person.weight;
		person.weight=temp;
		System.out.println("swap方法中 ,age="+person.age+" ,weight="+person.weight);
	}
}
public class Person {
	//定义两变量
	public int age;
	public int weight;
}

打印结果:

swap方法中 ,age=50 ,weight=23
交换后,age=50  ,weight=23

程序解析:程序从main方法开始执行,main方法开始创建了一个Person对象,并定义了一个person引用变量来指向Person对象,这个与基本类型不同。创建对象时,系统内存中有两个实体:堆内存中保存了对象本身,栈内存中保存了该对象的引用。紧接着给person对象赋值。  接下来,main方法中开始调用swap方法,此时main方法并没有结束,系统会分别开辟出main和swap两个栈区,分别用于保存mian方法和swap方法的局部变量。调用swap方法时,person变量作为实参,传入swap方法,同样采取值传递方式,把main方法中的person变量的值赋给swap方法里的person形参,从而完成swap方法的person形参初始化。这里需要指出的是,main方法中的person是一个引用(也就是指针),它保存的是Person对象的地址值,当person的值赋值给swap方法中的person形参后,swap方法中的person也是Person对象的地址值,同样也是指向堆内存中Person对象的地址。此时,不管是操作main方法中的person变量还是操作swap方法中的person变量,其实质都是操作它所引用的Person对象,它们操作的是同一个对象。当swap中将person对象的两个变量值进行了交换,那么mian方法中输出的person对象的属性同样也交换了的。


八:递归方法:

在一个方法体内调用它本身,被称为方法的递归,方法的递归包含一个中隐式的循环,它会重复执行某一段代码,但这种重复执行无须循环控制(递归一定要向已知方向递归)。


  

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yuanjian19900610/article/details/8648142

智能推荐

人工智能第三章(1)——无信息搜索(盲目搜索) (附书本资料)_无信息搜索又称为-程序员宅基地

文章浏览阅读8.8k次,点赞21次,收藏51次。这篇文章的意义在于哪里呢?1)向大家展示如何形式化定义一个搜索问题,又如何去求解;2)通过讲述各种盲目搜索算法,帮大家梳理无信息搜索的脉络。_无信息搜索又称为

【图像重建】基于小波变换结合BP、OMP、StOMP实现图像重建含MSE PSNR附Matlab代码-程序员宅基地

文章浏览阅读847次,点赞18次,收藏20次。图像重建是数字信号处理领域的一个重要问题,它涉及到从损坏或不完整的图像数据中恢复出高质量的图像。在图像重建的研究中,小波变换结合各种重建算法已经成为一个热门的研究方向。本文将介绍基于小波变换结合BP、OMP、StOMP算法实现图像重建,并对重建效果进行评估,包括均方误差(MSE)和峰值信噪比(PSNR)。小波变换是一种多尺度分析方法,它可以将信号分解成不同尺度的频率成分,从而更好地捕捉信号的局部特征。在图像重建中,小波变换可以将图像分解成不同尺度的小波系数,然后利用这些小波系数进行重建。

指针数组 数组指针 的判断_int*做参数如何判断是整型还是数组-程序员宅基地

文章浏览阅读685次。用变量a给出下面的定义:一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整型数*int a[10];这是一个指针数组。数组a里存放的是10个int型指针*int (a)[10];这是一个数组指针。a是指针,指向一个数组。数组a有10个int型元素。*int (a)(int);这个表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个函数,这个函数有一个类..._int*做参数如何判断是整型还是数组

Linux运维常用命令和正则表达式_linux cp命令加正则表达式-程序员宅基地

文章浏览阅读1k次。1.删除0字节文件find -type f -size 0 -exec rm -rf {} ;2.查看进程按内存从大到小排列ps -e -o “%C : %p : %z : %a”|sort -k5 -nr3.按cpu利用率从大到小排列ps -e -o “%C : %p : %z : %a”|sort -nr4.打印说cache里的URL_linux cp命令加正则表达式

rsa算法 c#语言,C#实现简单的RSA非对称加密算法示例-程序员宅基地

文章浏览阅读639次。本文实例讲述了C#实现简单的RSA非对称加密算法。分享给大家供大家参考,具体如下:界面控件namespace RSA算法{partial class Form1{/// /// 必需的设计器变量。/// private System.ComponentModel.IContainer components = null;/// /// 清理所有正在使用的资源。/// /// 如果应释放托管资源,为..._c# 非对称加密算法

Synonyms:一个开源的中文近义词工具包_synonyms.nearby-程序员宅基地

文章浏览阅读4.6k次,点赞4次,收藏8次。作者:Synonyms 项目的作者胡小夕是北京邮电大学研究生,目前实习于今日头条 AI LAB。从事自然语言处理方向研究,在智能客服,知识图谱等领域都有相关研究开发经验。工具包技术说明:该中文近义词工具包采用的基本技术是 Word2vec。Synonyms 的安装十分便捷,我们可以直接使用命令 pip install -U synonyms 完成。该工具包兼容 Python 2 和 Python ..._synonyms.nearby

随便推点

故障转移集群仲裁盘_Windows 2008故障转移集群之仲裁配置-程序员宅基地

文章浏览阅读1.2k次。(一)仲裁配置选项可以从四个可能的仲裁配置中选择:- 节点多数(推荐用于含有奇数个节点的群集)可以承受的故障节点数为节点数的一半(四舍五入)减去一。例如,七个节点的群集可以承受三个节点出现故障。- 节点和磁盘多数(推荐用于含有偶数个节点的群集)在见证磁盘保持联机时可以承受的故障节点数为节点数的一半(四舍五入)。例如,在见证磁盘联机时,六个节点的群集可以承受有三个节点出现故障。在见证磁盘脱机或出现故..._请对应选择故障转移群集仲裁配置描述正确的一项

Java用发送模板邮件,文本邮件,附件邮件(HTML模板)可附件可图片嵌套,以outlook邮件为例_java 邮件模板-程序员宅基地

文章浏览阅读6.8k次,点赞3次,收藏24次。发送邮件要提前准备好要发送的数据类容,还要提前将发件箱协议名,身份验证信息,服务主机名准备好以outlook邮箱为例,如图所示:在SMTP中可以看见相关设置。接下来直接上代码: //这个Map存放Html模板中的类容 Map<String, Object> emap = new HashMap(); emap.put("top0", "你好"); emap.put("top1", "11111"); ._java 邮件模板

手机开发实战188——手机软件开发注意事项2_188旅游v6.6手机版 移动端如何设置-程序员宅基地

文章浏览阅读452次。11提交代码控制和内存使用控制:模块:日期:关键词:修改原因:改动造成的功能上的变化:改动可能产生的隐患:文件:修改、增加和删除;函数:修改、增加和删除;涉及到的全局函数和变量:静态内存使用(申请和释放):动态内存使用(申请和释放): 12电话本的表示方式,如果有来电大头贴的功能,在结构体中保存_188旅游v6.6手机版 移动端如何设置

SpringCloud微服务实战——搭建企业级应用开发框架(一):架构说明_springcloud微服务实战——搭建企业级开发框架(一):微服务日志系统设计与实现-程序员宅基地

文章浏览阅读2k次,点赞3次,收藏19次。SpringCloud分布式应用微服务系统架构图:SpringCloud分布式应用微服务系统组件列表:微服务框架组件:Spring Boot2 + SpringCloud Hoxton.SR8 + SpringCloud AlibabaSpring Boot Admin: 管理和监控SpringBoot应用程序的微服务健康状态数据持久化组件:MySql + Druid + MyBatis + MyBatis-PlusMycat: 中间件实现数据库读写分离Seata: 分布式事务管理,跨服务的_springcloud微服务实战——搭建企业级开发框架(一):微服务日志系统设计与实现

Golang 获取当前可执行文件名_golang获取当前软件名-程序员宅基地

文章浏览阅读2.5k次。如果编译好的文件修改了文件名,又希望能正确打印usage信息等,就可以通过动态获取当前可执行程序文件名实现:func main() { path,_ := os.Executable() _,exec := filepath.Split(path) cmd := cobra.Command{ Use: exec, Short: "", Long: "",_golang获取当前软件名

双绞线接法心得-程序员宅基地

文章浏览阅读112次。标准568A:绿白—1,绿—2,橙白—3,蓝—4,蓝白—5,橙—6,棕白—7,棕—8标准568B:橙白—1,橙—2,绿白—3,蓝—4,蓝白—5, 绿—6,棕白—7,棕—8为了保持最佳的兼容性,普遍采用EIA/TIA568B标准来制作网线。所谓的差分信号是指一根线以正电平方式传输信号,另外一根线以负电平方式传输同一信号,当线路中出现干扰信号时,其对两根线的影响是相同的,因而在接收端还原差分信号时就可以屏蔽掉该干扰信号(可以理解为差分的两路信号执行减运算)。由于10M网卡能够使用按100M方式制作的网线;

推荐文章

热门文章

相关标签