为什么从子类访问父类变量直接通过属性来访问变量,变量就必须放在

拒绝访问 | www.csxtedu.com | 百度云加速
请打开cookies.
此网站 (www.csxtedu.com) 的管理员禁止了您的访问。原因是您的访问包含了非浏览器特征(a643a7-ua98).
重新安装浏览器,或使用别的浏览器主题 : 为什么从子类直接通过属性来访问变量,变量就必须放在头文件中?
级别: 新手上路
UID: 291116
可可豆: 17 CB
威望: 28 点
在线时间: 4(时)
发自: Web Page
为什么从子类直接通过属性来访问变量,变量就必须放在头文件中?&&&
画红线的那一段怎么理解?什么叫通过属性访问?有例子么?为什么从子类直接通过属性来访问变量,变量就必须放在头文件中?谢谢
级别: 精灵王
可可豆: 24891 CB
威望: 25992 点
在线时间: 3388(时)
发自: Web Page
简单的讲就是私有变量和公有的区别
这个说放.h的意思就是公有,放.m就是私有的意思。
lz如果实在理解不过来,可以不用太纠结,先往下看,看到后面就会慢慢体会了
级别: 新手上路
UID: 291116
可可豆: 17 CB
威望: 28 点
在线时间: 4(时)
发自: Web Page
就是说放.h里就是默认的@protect,放.m里相当于@private?
级别: 精灵王
可可豆: 24891 CB
威望: 25992 点
在线时间: 3388(时)
发自: Web Page
恩,是的。差不多是这个意思但是实际上有差别,因为properties里可以设置相关的具体参数
级别: 新手上路
UID: 291116
可可豆: 17 CB
威望: 28 点
在线时间: 4(时)
发自: Web Page
properties是哪一部分的内容呢?和@property是一回事么?
级别: 精灵王
可可豆: 24891 CB
威望: 25992 点
在线时间: 3388(时)
发自: Web Page
就是@property这部分,比如设定strong, weak, readonly等
级别: 新手上路
UID: 291116
可可豆: 17 CB
威望: 28 点
在线时间: 4(时)
发自: Web Page
恩,懂了,非常感谢~
级别: 新手上路
可可豆: 81 CB
威望: 1 点
在线时间: 18(时)
发自: Web Page
也可以放在.m文件里,但是在.h文件里加上,@class 类名 就行了
级别: 新手上路
UID: 291116
可可豆: 17 CB
威望: 28 点
在线时间: 4(时)
发自: Web Page
@class不是用来代替#import的么?
级别: 侠客
UID: 285890
可可豆: 442 CB
威望: 384 点
在线时间: 663(时)
发自: Web Page
.m文件里,在@implementation 类名 和@end 之间不能写@&property的,其实属性是写在了上面的类别或扩展里面即@interface 类名 ()和@end之间;
&私有和共有,我觉得是这个变量 &你有没有公开 set 、get方法的问题,有了话,其他类就操纵这个变量的数据了,和写在哪没关系。用@&property来定义变量是还会一起创建 get\set方法的
& 我也是新手,这是我的理解。
关注本帖(如果有新回复会站内信通知您)
发帖、回帖都会得到可观的积分奖励。
按"Ctrl+Enter"直接提交
关注CocoaChina
关注微信 每日推荐
扫一扫 关注CVP公众号
扫一扫 浏览移动版一、多态的表现形式
多态的表现形式有方法重载,方法改写,多态变量和泛型。重载是一种静态的多态性,在程序编译时确定被调用的方法,称为早绑定。而多态变量和改写相结合之后,方法的调用在运行时才能确定,是动态的多态性,称为晚绑定。
二、里氏替换原则(The Liskov Principle of Substitution)
在静态类型语言中,在父类和子类之间的关系存在下面的现象:
子类的实例必须拥有父类的所有数据成员;
子类的实例必须至少通过继承(如果不是显示地改写)实现父类所定义的所有功能;
这样,在某种条件下,如果用子类实例来替换父类实例,那么将会发现子类实例可以完全模拟父类的行为,二者毫无差别;
替换原则是指如果有A和B两个类,类B是类A的子类,那么在任何情况下都可以用类B来替换类A,而外界则毫无察觉。
不是所有继承产生的子类都符合替换原则,符合替换原则的子类称为子类型。
三、静态类型和动态类型
在静态类型面向对象语言中,一个变量所存储的值的类型并不等同于这个变量所声明的类型。声明为父类类型的变量可以包含子类的实例值。
静态类型是指变量在声明时所确定的类型,并且一经声明就不会改变;动态类型是指这个变量实际存储的值的类型。在静态类型的面向对象程序设计语言中,在编译时消息传递表达式的合法性不是基于接收器的动态类型,而是基于接收器的静态类型。而对象对消息的响应取决于对象的动态类型。(就是说:写代码的时候“点”不出该对象动态类型包含而静态类型不包含的变量、方法;动态类型就是程序运行过程中被重新赋值为对其他对象的引用,这时候他就可以含有动态类型对象的方法了。)
这样的变量在多态中称为多态变量。
考虑下面的类图:
对应的程序如下:
class SuperClass {&&&&&&&&&& public void f1() {&&&&& }&&&&& public void f2() {&&&&& }}class SubClass extends SuperClass{&&&&&&&&&& public void f1() {&&&&& }&&&&& public void f3() {&&&&& }}public class Test{&&&&& public static void main(String[] args){&&&&&&& SuperClass ob=new SuperClass(); //(1)&&&&&&& ob=new SubClass();& //(2)&&&&&&& ob.x=1;& //(3)&&&&&&& ob.y=2;& //(4)&&&&&&& ob.f1(); //(5)&&&&&&& ob.f2(); //(6)&&&&&&& ob.f3(); //(7)&&&&& }}
程序中,子类改写了父类中的f1()方法,添加了自己的属性y和方法f3()。语句(1)中变量ob的静态类型是SuperClass,动态类型是SuperClass;语句(2)中变量ob的静态类型不变,动态类型是SubClass(子类类型),子类对象的地址可以存放在父类类型的引用变量中,即父类引用变量引用子类对象;(3)、(5)、(6)是正确的,(4)、(7)是错误的,因为对于引用的合法性依赖于变量的静态类型,属性y和方法f3()在SuperClass中不存在,故有错,还应该注意参数的匹配;(5)调用的f1()是子类的f1(),(6)调用的f2()是父类的f2(),这是因为对于消息的响应取决于变量的动态类型,因此f1()是SubClass中的f1()。
如果在父类和子类中存在属性的覆盖,则通过ob(父类对象名)访问的x是父类中被覆盖的属性。
class SuperClass {&&&&& public int x=1;&&&&& public void f1() {&&&&& }&&&&& public void f2() {&&&&& }}class SubClass extends SuperClass{&&& public int x=2;&&&&&&&&&& public void f1() {&&&&& }&&&&& public void f3() {&&&&& }}class Test{&&&&& public static void main(String[] args){&&&&&&& SuperClass ob=new SuperClass(); //(1)&&&&&&& ob=new SubClass();& //(2)&&&&& System.out.println(ob.x);&&&&&&& ob.f1(); //(5)&&&&&&& ob.f2(); //(6)&&&&& }}显示结果为:1
四、父类对象和子类对象
子类从父类继承了所有的属性和方法,因此作用在父类上的方法应用在子类对象上也是合法的。由于继承表达的是一种is a关系,即子类对象可以被视为父类的一个对象,因此可以把子类对象的引用赋给父类对象;反之,父类对象不一定是其某个特定子类的对象,因此不一定满足is a关系,因此不能把父类对象的引用直接赋给子类对象。
class Employee {&& private S&&&&&&& Employee(String name,int salary){&&&&&&&& this.name=&&&&&&&& this.salary=&& }&&&&&& public String getDetails() {&&&&&&&& return Name: " + name + "\nSalary: " +&& }}&& class Manager extends Employee {&& S&&&&& Manager(String name,int salary,String department){&&&&&&&& super(name,salary);&&&&&&&& this.department=&& }&&&&&& public String getDetails() {&&&&&&&&& return super.getDetails() + "\nDepartment: " +&& }}&& public class Test{&& public static void main(String args[]){&&&&&&&& Employee a=new Employee("Mike",800);&&&&&&&& Manager b=new Manager("Tom",1200,"Research");&&&&&&&& Manager c=a; //Error&&&&&&&& Employee d=b; //True&&&&&&&& System.out.println(A.getDetails());&&&&&&&&& System.out.println(D.getDetails());&& }}
根据消息传递的概念,对消息的响应取决于接收器。而这又依赖于接收器的动态类型。因此,当父类对象中存放了子类对象的引用,并且父类和子类中有方法覆盖时,通过父类对象将会调用子类中的方法。
同时,在编译时消息传递表达式的合法性不是基于接收器的动态类型,而是基于接收器的静态类型。因此,当父类对象中存放了子类对象的引用时,不能通过父类对象名引用子类中新定义的成员(包括属性和方法)。例如,下面的语句是错误的:
System.out.println(d.department);
可以通过强制类型转换把父类对象转换成子类对象,然后再进行访问:
Manager e=(Manager)
System.out.println(e.department);
五、运行时类型识别和向下造型
替换原则将数据的类型从子类提升到了父类。有时也需要做相反的事情,例如判断父类对象所存放的值是否是某个子类的对象。
类型的强制类型转换只能用于子类唯一这种确定的情况下,如果子类不止一个,则可能发生错误,可以通过instanceof运算符来识别子类对象所属的类。
public class Manager extends Employee
public class Contractor extends Employee
假设有一个子类对象,可以通过下面的语句来判断它所述的类并执行相应的操作:
if(a instanceof Manager){
Manager b=(Manager)
......
}
else if(a instance of Contractor){
Contractor b=(Contractor)
......
}
例如在上面的操作中,可以把a这个父类对象转换成相应的子类对象,从而去访问子类中新增的属性或方法,这称为向下造型(down casting)。造型(cast)也就是通常所说的类型转换。类型的提升称为向上造型(up casting)。
六、多态和抽象类、抽象方法
抽象类不能实例化,但是可以声明抽象类的变量用以存放其子类对象的引用。另外,抽象方法为其子类规定了一个必须实现的接口,这样在多个子类中就拥有一个相同的接口方法。
在程序中可以定义一个父类的数组用于保存所有子类的对象,从而保持程序的简洁和灵活性。下面的程序说明了这个问题。
abstract class Shape{&&& public abstract void draw();}class Circle extends Shape{&&&&&&&&&&&& public Circle(int x,int y,int radius){&&&&&&& this.x=x;&&&&&&& this.y=y;&&&&&&& this.radius=&&& }&&& public void draw() {&&&&&&& System.out.println("draw circle: ("+x+","+y+"),radius="+radius);&&& }}class Line extends Shape{&&&&& private int x1,y1,x2,y2;&&&&& public Line(int x1,int y1,int x2,int y2){&&&&&&& this.x1=x1;&&&&&&& this.x2=x2;&&&&&&& this.y1=y1;&&&&&&& this.y2=y2;&&&&& }&&&&& public void draw(){&&&&&&& System.out.println("draw line,("+x1+","+y1+")-("+x2+","+y2+")");&&&&& }}public class TestShape{&&&&& public static void main(String[] args){&&&&&&& Shape[] s=new Shape[4];&&&&&&& s[0]=new Circle(1,1,10);&&&&&&& s[1]=new Line(3,4,20,12);&&&&&&& s[2]=new Circle(3,10,20);&&&&&&& for(int i=0;i&s.i++){&&&&&&&&& if(s[i]!=null)&&&&&&&&&&& s[i].draw();&&&&&&& }&&&&& }}
如果没有多态这个特性或者不利用多态这个特性,则程序将复杂得多。
Java中所有的类的最终根类是java.lang.Object,因此可以Object类型的引用变量可以存放所有Java对象的引用,也使用一个Object数组保存Java中所有的对象。
浏览: 2350395 次
来自: 南京
麻烦问下,“获取每个Item相似性最高的前N个Item”,这个 ...
Java读源码之Netty深入剖析网盘地址:https://p ...
[size=medium][b]“更新一个文档”这部分的说法错 ...
以后看看,谢谢
(window.slotbydup=window.slotbydup || []).push({
id: '4773203',
container: s,
size: '200,200',
display: 'inlay-fix'java基础:父类与子类之间变量和方法的调用
1)父类构造函数
java中当调用某个类的构造方法的时候,总会调用父类的非静态初始化块进行初始化,这个调用是隐式的,而且父类的静态初始化代码
块总是会被执行,接着调用父类的一个或者多个构造器执行初始化,这个调用也可以通过super进行显式调用。
父类代码如下:
public class Creature {//父类
{//非静态代码块
System.out.println(&creature的非静态代码块正在执行&);
public Creature(){
System.out.println(&creature的构造函数正在执行&);
子类代码如下:
public class Animal extends Creature {
System.out.println(&animal的初始化代码块正在执行&);
public Animal(){
System.out.println(&animal的构造方法正在执行&);
public static void main(String[] args){
Animal a = new Animal()& ;
则运行程序后的结果为:
creature的非静态代码块正在执行
creature的构造函数正在执行
animal的初始化代码块正在执行
animal的构造方法正在执行
从结果中可以看出:调用某个类的构造方法的时候总是会先执行父类的非静态代码块,然后执行父类的构造方法,最后才是执行当前类的
非静态代码块和构造方法。执行过程中有先后顺序。
若果想要显式调用父类的构造方法则可以使用super(),来调用,但是super关键字和this关键字都必须放在构造放的第一行,而且只能使
用一个,为什么要放在第一行呢?因为如果不放在第一行则先调用子类的初始化代码,再调用父类的初始化代码,则父类中的初始化后的值
会覆盖子类中的初始化的值。
注:super用于显式调用父类的构造器,this可以显式调用本类中的重载的构造器。
2)访问子类对象的实例变量
子类的方法可以访问父类中的实例变量,这是因为子类继承父类就会获得父类中的成员变量和方法,但是父类方法不能访问子类的实例变量
,因为父类根本无法知道它将被哪个类继承,它的子类将会增加怎么样的成员变量。但是,在极端的情况下,父类也可以访问子类中的变量。
父类代码如下:
public class Base {//父类
private int i = 2 ;
public Base(){
this.display() ;
public void display(){
System.out.println(i);
子类中代码如下:
public class Derived extends Base {
private int i = 22 ;
public Derived(){
public void display(){
System.out.println(i);
测试用例如下:
public class Test {
public static void main(String[] args) {
new Derived() ;
程序的执行结果为:
也许你会感到奇怪,为什么不是2?22?222?怎么会是0呢,下面我们看一下程序的执行过程。当我们调用new Derived() ;创建Derived
实例的时候,系统会为Derived对象分配内存空间,Derived会有两个i实例变量,会分配两个空间来保存i的值。分配完空间以后i的值为0
,如果有引用类型则引用类型的值为null。接下来程序在执行Derived的构造器之前会执行Base的构造器,表面上看Base的构造器中只有
一行代码,但是在父类中定义i的时候执行的初始值2,因此经过编译之后,该构造方法中应该包含如下两行代码:
this.display() ;
程序先将Base中的i赋值为2,然后执行display方法。此处有一个关键字this,this到底代表谁呢?表面上看this代表的是Base的当前实例,
但是实际上代码是放在Derived的构造器中的,所以this最终代表的是Derived的当前实例(编译类型是Base而实际引用一个Derived对象),
所以如果在父类的构造方法中直接输出System.out.println(this.i) ;则输出的结果为2。但是调用this.display()方法,此时调用的是
子类中重写的display方法,输出的变量i也是子类中的i,但是此时子类中的变量i还没有赋值,所以输出结果为0。
为了详细的看清楚this变量到底代表什么实例,我们将Base的构造方法修改如下:
public Base(){
System.out.println(this.i);
System.out.println(this.getClass());
this.display() ;
再次运行程序,结果为:
class edu.qichao.chapter2.Derived
可以看到this代表的是Derived的实例,但是编译的时候类型为Base,所以输出this.i的值为2。
3)调用被子类重写的方法
默认情况下,子类可以调用父类的方法,但是父类不能调用子类的方法,因为父类不知道它将被哪个子类继承,也不知道子类将增加怎么
样的方法。
父类Animal的代码如下:
public class Animal {
public Animal(){
this.desc = getDesc() ;
public String getDesc(){
return &Animal& ;
public String toString(){
子类Wolf的代码如下:
public class Wolf extends Animal {
public Wolf(String name , double weight){
this.name =
this.weight =
public String getDesc(){
return &Wolf[name=& + name + &,weight=& + weight + &]& ;
public static void main(String[] args){
System.out.println(new Wolf(&灰太狼& , 3));
程序的运行结果为:
Wolf[name=null,weight=0.0]
现在我们分析一下程序执行的过程。在main方法中通过new Wolf(&灰太狼& , 3);来创建一个Wolf的实例,子类会隐式调用父类的构造方
法,在父类构造方法中初始化desc变量this.desc = getDesc() ;此处需要注意this变量,虽然这个this放在Animal的构造放中,但是是在
Wolf的构造方法中调用父类的构造方法,所以this编译时类型为Animal,运行时类型为Wolf,此处调用的getDesc方法是子类Wolf的方法,
但是子类中的name和weight变量都没有初始化,默认为null和0.0.所以程序的最终结果为:Wolf[name=null,weight=0.0]
4)继承成员变量和成员方法的区别
java中队成员变量的继承和成员方法的继承是不同的。
父类代码如下:
public class Base {
int count = 2 ;
public void display(){
System.out.println(this.count);
子类代码如下:
public class Derived extends Base {
int count = 20 ;
public void display(){
System.out.println(this.count);
测试用例如下:
public class Test {
public static void main(String[] args) {
Base b = new Base() ;
System.out.println(b.count);
b.display() ;
System.out.println(&-----------------&);
Derived d = new Derived() ;
System.out.println(d.count);
d.display() ;
System.out.println(&-----------------&);
Base bd = new Derived() ;
System.out.println(bd.count);
bd.display() ;
System.out.println(&-----------------&);
Base d2b =
System.out.println(d2b.count);
程序运行结果为:
-----------------
-----------------
-----------------
在上面的程序中,不管是d变量、还是bd变量、还是都d2b变量。只要他们指向一个Derived对象,则不管他们声明时用了什么类型,当通过
这些变量调用方法时,方法的行为总是表现出他们的实际类型的行为,但是如果通过这些变量来访问他们所指向对象的实例变量的时候,
这些实例变量的值总是表现出声明这些变量所用类型的行为。由此可见,java处理成员变量和成员方法的继承时是有区别的。
摘自 xxqi1229的专栏&|&&|&&|&&|&&
当前位置: >
【OC】权限的概念
作者:chenglibin1988 & 来源:转载 &
摘要: OC权限的概念:1实例变量:在子类的实现文件中不能直接访问父类的私有变量(但能通过setter、getter方法访问到),不能直接访问的意思就是说,我在父类中定义了一个私有的实例变量,名称是_name,在子类的实现文件中不能直接通过_name这种方式访问,比如:在初始化函数中写_name=就是错误的,但是在@protected属性的变量就可以这么使用,这是将实例变量声明为@private
OC 权限的概念:
1 实例变量:在子类的实现文件中不能直接访问父类的私有变量(但能通过setter、getter方法访问到),不能直接访问的意思就是说,我在父类中定义了一个私有的实例变量,名称是 _name,在子类的实现文件中不能直接通过 _name 这种方式访问,比如:在初始化函数中写 _name =就是错误的,但是在@protected属性的变量就可以这么使用,这是将实例变量声明为@private和非prote的唯一区别;
2 实例方法:其它面向对象语言比如C++和Java的区别是 OC里面的方法没有公有、私有等权限这一说法,意思是不能够显示的将方法声明为 私有或者其它权限,但是OC有一个相对私有的概念,就是不在头文件中声明,只在实现文件中实现,这样基本就保证了定义的这样一种方法只能够在当前类中使用,而基本不会被子类调用。为什么都是说基本?其实子类还是看能够调用这个相对私有的只在类的实现文件中定义的方法的,但前提是要求调用者知道那个未被声明的方法的方法名,意思就是可以访问,但是有一定门槛。
3 OC的子类能够继承父类除了私有变量以外的所有东西。
版权所有 IT知识库 CopyRight (C)
IT知识库 IT610.com , All Rights Reserved.

我要回帖

更多关于 子类能不能访问父类的私有变量 的文章

 

随机推荐