引入
在java编程语言中,类型转换(无论是强制类型转换还是自动类型转换)的方向并不是简单地基于“高位”和“低位”的概念,而是基于数据类型的范围和精度。
基本类型强制转换
1.数字之间
short s = 100; int i = s; // 自动类型转换,安全 int j = 30000; // 一个大于short类型能表示的最大值的int short k = (short) j; // 强制类型转换,可能导致数据丢失
上面给出了两种数值转换的概念,第一种是short转成int类型,由于short是16位的,int是32位的,此时就是低精度转为高精度,所以编译器会自动进行类型转换,是安全的,不用强转(因为这种转换是安全的,不会丢失任何信息,只是简单地扩展了符号位)
而第二种则是让int类型转成short,高精度转低精度,不安全,强制类型转换,short只能存储低16位的数据,高16位的位置就舍弃了,所但凡int的高16位存有数据,此时的强转就会发生数据丢失。
所以通常而言,这种高精度强转低精度是没有意义的。
2.数字字符之间
引入
以前有涉及过steam,buffer的概念,并且它们本质都是数组。
int c=23456; char d=(char) c; //将int类型的c强转成char类型的d system.out.println(d); //并且能够解析输出
steam就是类似如下的一串二进制数字,在解析时以8位或32位等解析成十进制,就可以得到不同的结果:
int[] arr={23456,23457,34567,23876,32447}; for(int x:arr){//解析输出 char e=(char) x; system.out.println(e); }
【以上就是两个基本类型强制转换的例子,而且基本类型之间都可以进行强转,只是有的没有意义。】
引用类型的强制转换
引入多态概念前提
e.g.首先,我们定义一个父类
animal
,并在其中声明一个方法makesound
,但不在父类中实现它(可以将它设为抽象方法,但在这个例子中,我们为了简化,让它返回一个默认字符串)。然后,我们创建两个子类dog
和cat
,它们都继承自animal
类,并各自实现了makesound
方法。
// 父类 animal class animal { // 可以是一个抽象方法,但这里为了简化,我们提供一个默认实现 public string makesound() { return "some generic animal sound"; } } // 子类 dog 继承自 animal class dog extends animal { @override public string makesound() { return "woof! woof!"; } } // 子类 cat 继承自 animal class cat extends animal { @override public string makesound() { return "meow! meow!"; } } public class polymorphismexample { public static void main(string[] args) { // 使用父类类型的引用来指向子类对象 animal mydog = new dog(); animal mycat = new cat(); // 调用被重写的方法,将展示多态性 system.out.println(mydog.makesound()); // 输出: woof! woof! system.out.println(mycat.makesound()); // 输出: meow! meow! // 尽管 mydog 和 mycat 都是 animal 类型的引用, // 但它们实际上指向的是 dog 和 cat 对象, // 因此调用 makesound 方法时会执行子类中的实现。 } }
在这个例子中,展示了多态性的两个关键方面:
父类引用指向子类对象:
mydog
是一个animal
类型的引用,但它实际上指向了一个dog
对象。同样,mycat
是一个animal
类型的引用,但它指向了一个cat
对象。方法重写:
dog
和cat
类都重写了animal
类中的makesound
方法。因此,当通过mydog
和mycat
引用调用makesound
方法时,会分别调用dog
和cat
类中的实现。以上例子展示了多态所遵守的两项,下面是完整的多态遵循条件:
要符合多态,通常需要满足以下几个条件:
继承:多态通常依赖于继承关系。在面向对象编程中,子类继承父类,从而可以重用父类的代码并扩展新的功能。多态性允许我们使用父类类型的引用来引用子类对象。
方法重写(override):子类需要重写父类中的某些方法,以便在调用这些方法时能够表现出不同的行为。方法重写是多态性的关键所在,它允许子类提供父类方法的具体实现。
父类引用指向子类对象:这是多态性的另一个重要方面。我们可以创建一个父类类型的引用,并将其指向一个子类对象。当通过这个引用调用一个被重写的方法时,将调用子类中的该方法实现,而不是父类中的实现。
接口或抽象类:虽然多态性不一定需要接口或抽象类,但它们为多态性提供了强大的支持。接口和抽象类可以定义方法签名,而不提供具体实现。子类可以实现这些接口或继承这些抽象类,并提供具体的方法实现。这样,当使用接口或抽象类类型的引用来引用子类对象时,就可以实现多态性。
运行时类型识别(rtti, run-time type identification):在java等语言中,运行时类型识别是多态性的基础之一。它允许程序在运行时确定对象的实际类型,并根据这个类型来调用相应的方法。这是通过方法重写和父类引用指向子类对象来实现的。
【注意:虽然给出了这么多条件,但是多态性的核心在于方法重写和父类引用指向子类对象(句柄可以指向自己类的对象或者自己的子孙后代类的对象)这两个方面。】
【注意:引用类型之间的强制类型转换就没有这么自由了,会有诸多限制】
如下两个子类继承person父类:
【注意:遵循一个类的句柄可以指向自己类的对象或者自己的子孙后代类的对象】
所以以下两种表达方式是错误的:
①直接报错:
②运行时报错:
运行时报错是因为不符合多态,即“指向自己类的对象或者自己的子孙后代类的对象”,这里表示的是:
将s(指向child2
实例的person
类型变量)强转换成child 3,child2和child3是兄弟关系,不符合多态。
如何解决以下问题呢?(o ∀ o )
有啦!!就用那招!(・∀・(・∀・*)
引入关键字instanceof:
instanceof
是一个用于检查对象是否为特定类或其任何父类的实例的关键字。这个操作符返回一个布尔值:如果对象是指定类的实例,或者是该类的任何子类的实例,则返回true
;否则返回false
。if (object instanceof classname) { // 对象是指定类的实例或其子类的实例时执行的代码 }其中:
object
是要检查的对象classname
是要检查的类名(包括接口名)还不理解没关系,以下给出一个实例:
class animal {} class dog extends animal {} class cat extends animal {} public class main { public static void main(string[] args) { animal mydog = new dog(); //animal mydog = new dog(); 创建了一个 dog 类的实例,并将其引用赋值给 animal 类型的变量 mydog。这意味着 mydog 指向的是一个 dog 对象,但它在编译时被视为 animal 类型。 animal mycat = new cat(); // animal mycat = new cat(); 类似地,创建了一个 cat 类的实例,并将其引用赋值给 animal 类型的变量 mycat。 system.out.println(mydog instanceof dog); // 输出 true system.out.println(mydog instanceof animal); // 输出 true system.out.println(mydog instanceof cat); // 输出 false system.out.println(mydog instanceof object); // 输出 true system.out.println(null instanceof animal); // 输出 false } }
在这个示例中,
mydog
是dog
类的实例,也是animal
类和object
类的实例(因为所有类都继承自object
)。因此,mydog instanceof dog
返回true
,mydog instanceof animal
也返回true
,但mydog instanceof cat
返回false
,因为mydog
不是cat
的实例。同样地,null
不是任何类的实例,所以null instanceof animal
返回false
。
public class test{ public static void main(string[] mmm) throws exception{ child2 x=new child2(); //child2 x = new child2(); 创建了一个 child2 类的实例,并将其引用赋值给 child2 类型的变量 x。 child3 w=new child3(); //child3 w = new child3(); 创建了一个 child3 类的实例,并将其引用赋值给 child3 类型的变量 w。 //句柄可以指向自己类的对象或者自己的子孙后代类的对象 person s=x; //父类指子类child2 m1(s); s=w; m1(s); public static void m1(person s){ child3 w=null; if(s instanceof child3){ //⭐使用instanceof关键字检查s是否是child3的实例,如果是true,才进行下面的强转代码 //⭐用instanceof来验证强转⭐ w=(child3) s; } } } }
可以看见上面对m1() 方法进行了两次调用。
如果 s
指向的是 child3
实例(在第二次调用 m1(s);
时),条件为真,代码块内的强转类型转换 w = (child3) s;
会执行。如果 s
指向的是 child2
实例(在第一次调用 m1(s);
时),条件为假,代码块内的代码不会执行。
总结
到此这篇关于java强制转化的文章就介绍到这了,更多相关java强制转化内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论