归根结底,当访问一个字段时,您会在立即键入时访问它。在这种情况下,当您有一个字段类型为接口时:IShoulders,您只能直接访问接口定义的任何属性/方法。当您访问一个定义为实现相同接口的类的字段时,这个新字段(定义和访问为RightHand)不仅提供对IShoulders 定义的那些属性/方法的访问,还提供对由定义的扩展属性/方法的访问班级RightHand。
根据您的定义,除了move() 打印出的值之外,这里没有真正的区别,但进行以下更改:
public class RightHand implements IShoulders {
public void move(){
System.out.println("Move Right Hand");
}
public void Gesture()
{
System.out.println("Make a gesture with Right Hand");
}
}
新的Gesture 方法只能被定义为RightHand 的字段访问,它不会存在于仅定义为IShoulders 的字段上,即使您使用new RightHand() 分配字段,您需要将字段装箱或转换为 RightHand 才能访问新方法。
鉴于上述RightHand 类定义,请尝试以下操作:
IShoulders shoulder = new RightHand();
shoulder.move(); // this will work fine...
shoulder.Gesture(); // this will not be possible as "Gesture()" does not exist on IShoulders.
((RightHand)shoulder).Gesture(); // this will work after casting shoulder as RightHand
// since the underlying object is actually a RightHand.
然后尝试以下操作:
RightHand rhand = new RightHand();
rhand.move(); // again, this works fine...
rhand.Gesture(); // this now works fine too..
此外,接口是实现它的任何类的约定。它只是说,如果一个类实现了一个接口,它必须实现该接口中的所有内容。然而,它没有说明它应该如何实施。因此,只要类实现了接口的结构,这些实现的内容就可以完全定制到每个单独的类。
实现接口的替代方法是使用子类创建派生类。这看起来类似于实现接口,但是基类已经实现了属性和方法。它们可以被覆盖,除非您不使用 virtual 装饰它们,或者在另一个继承级别上覆盖并使用 final 装饰。
我很抱歉,但让我们缓和一下,因为它仍然有点令人困惑。
当我写 IShoulder rightHand 或 RightHand rightHand 时,我正在定义
创建对象之前的类型?我也一直想问
如果我们仍然使用 new 关键字,为什么我们需要定义一个类型
就像我们对任何其他对象(如集合)所做的那样?列表 mylist =
new list 以及如何口头解决这个问题?像对象右手的
RightHand 类封装 RightHand/IShoulder?如果我纠正我
错了——eersteam
当然,对于键入变量 - 这允许编译器(和程序员,就此而言)强烈定义可以使用的内容,以及如何将其用于对象/值。一个简单的例子是一个函数:
public string HyphenateTwoWords(string word1, string word2)
{
return string.Format("{0}-{1}", word1, word2);
}
上述函数接受两个string 参数,并用连字符将它们连接在一起。如果参数的类型不是string,那么任何东西都可以传入,结果在某些情况下可能只是错误的,或者在其他情况下抛出异常。由于它们被定义为string,因此string.Format() 调用的执行没有任何问题。
现在,在 C# 和其他语言中,您实际上可以使用 var 泛型定义字段/变量,例如:
List<string> myStringList = new List<string>();
myStringList.Add("Test1");
myStringList.Add("Test2");
myStringList.Add("Test3");
foreach(var item in myStringList)
Console.WriteLine(item);
这让编译器可以根据分配给它的内容推断item 的实际类型。但是,在大多数情况下,您并不想使用var。如果没有其他原因,最好显式键入您的变量,以提高可读性。查看变量的类型要容易得多,尤其是当您使用由多个开发人员维护的代码时。此外,显式键入变量可确保按预期使用,否则将引发可处理的异常,或者编译器将在构建解决方案时引发错误或警告。
现在,关于您的上述评论:
...我怎么知道它是左手还是右手?
在我的例子中,手不是肩膀,而是手应该是
附在应该是因为肩膀使他们能够移动。
那么你将如何实现呢? – eersteam
让我们设计一些接口和类来说明它们的用途,我将对您已经拥有的内容进行一些更改/添加所有这些都应该是相当简单的 - 看看Body 类上的AddLegs() 方法和看看LeftLeg 类。
public class BodyConstructor
{
public interface IBody
{
int Age { get; set; }
string Species { get; set; }
BodyPartGroup Head { get; set; }
BodyPartGroup Thorax { get; set; }
BodyPartGroup Abdomen { get; set; }
BodyPartGroup Pelvis { get; set; }
}
public interface IBodyPartGroup
{
BodyPartGroupType Type { get; set; }
List<IBodyPart> BodyParts { get; set; }
}
public interface IBodyPart
{
LateralDirection LateralOrientation { get; set; }
string Name { get; set; }
List<IBodyPart> SubParts { get; set; }
void Move();
}
public enum BodyPartGroupType
{
Head = 1,
Thorax = 2,
Abdomen = 3,
Pelvis = 4,
}
public enum LateralDirection
{
Central = 0,
Right = 1,
Left = 2,
}
public class Body : IBody
{
public Body()
{
Head = new BodyPartGroup(BodyPartGroupType.Head);
Thorax = new BodyPartGroup(BodyPartGroupType.Thorax);
Abdomen = new BodyPartGroup(BodyPartGroupType.Abdomen);
Pelvis = new BodyPartGroup(BodyPartGroupType.Pelvis);
}
public Body(int age, string species)
: this()
{
Age = age;
Species = species;
}
public int Age { get; set; }
public string Species { get; set; }
public BodyPartGroup Head { get; set; }
public BodyPartGroup Thorax { get; set; }
public BodyPartGroup Abdomen { get; set; }
public BodyPartGroup Pelvis { get; set; }
public void AddLimbs()
{
AddArms();
AddLegs();
}
public void AddArms()
{
// Individual segments for the left arm
BodyPart leftShoulder = new BodyPart("Left Shoulder", LateralDirection.Left);
BodyPart leftArm = new BodyPart("Left Arm", LateralDirection.Left);
BodyPart leftHand = new BodyPart("Left Hand", LateralDirection.Left);
leftArm.SubParts.Add(leftHand);
leftShoulder.SubParts.Add(leftArm);
// Individual segments for the right arm
BodyPart rightShoulder = new BodyPart("Right Shoulder", LateralDirection.Right);
BodyPart rightArm = new BodyPart("Right Arm", LateralDirection.Right);
BodyPart rightHand = new BodyPart("Right Hand", LateralDirection.Right);
rightArm.SubParts.Add(rightHand);
rightShoulder.SubParts.Add(rightArm);
// Add arms to thorax
Thorax.BodyParts.Add(rightShoulder);
Thorax.BodyParts.Add(leftShoulder);
}
public void AddLegs()
{
// Individual segments for the left leg
BodyPart leftHip = new BodyPart("Left Hip", LateralDirection.Left);
LeftLeg leftLeg = new LeftLeg(); // Here we use the LeftLeg class instead, which inherits BodyPart
BodyPart leftFoot = new BodyPart("Left Foot", LateralDirection.Left);
leftLeg.SubParts.Add(leftFoot);
leftHip.SubParts.Add(leftLeg);
//Individual segments for the right leg
BodyPart rightHip = new BodyPart("Right Hip", LateralDirection.Right);
BodyPart rightLeg = new BodyPart("Right Leg", LateralDirection.Right);
BodyPart rightFoot = new BodyPart("Right Foot", LateralDirection.Right);
rightLeg.SubParts.Add(rightFoot);
rightHip.SubParts.Add(rightLeg);
// Add legs to pelvis
Pelvis.BodyParts.Add(leftHip);
Pelvis.BodyParts.Add(rightHip);
}
}
public class BodyPartGroup : IBodyPartGroup
{
public BodyPartGroup()
{
BodyParts = new List<IBodyPart>();
}
public BodyPartGroup(BodyPartGroupType type)
: this()
{
this.Type = type;
}
public BodyPartGroupType Type { get; set; }
public List<IBodyPart> BodyParts { get; set; }
}
public class BodyPart : IBodyPart
{
public BodyPart()
{
SubParts = new List<IBodyPart>();
}
public BodyPart(string name, LateralDirection orientation)
: this()
{
Name = name;
LateralOrientation = orientation;
}
// Location of body part: Left, Central, Right
public LateralDirection LateralOrientation { get; set; }
public string Name { get; set; }
public List<IBodyPart> SubParts { get; set; }
public virtual void Move()
{
// Common body part movement code.
}
}
public class LeftLeg : BodyPart
{
public LeftLeg()
{
Name = "Left Leg";
LateralOrientation = LateralDirection.Left;
}
public override void Move()
{
// Custom left leg move code
base.Move(); // Call base BodyPart.Move();
}
}
}