عملية التلبيس أو القولبة Typecast or typecasting:
تحويل النوع في مجال برمجة الكمبيوتر، هو عملية أو نتيجة لتغيير نوعية البيانات لكيان من نوعية إلى نوعية أخرى ، و بمعنى اخر تغيير نوع البيانات من نوع إلي نوع اخر في وقت التحويل البرمجي بدون التقييد بنوع معين وبدون التغيير في قيمتها إلا في حالات معينة فقط.

في عملية تلبيس او قولبة كائن جافا (typecasting) يمكن لمرجع كائن ان يتم تلبيسه او قولبته في مرجع كائن آخر.

التلبيس او القولبة يمكن أن تكون للفئة نفسها أولأحد الفئات الفرعية، أو الفئة المتفوقة أو الواجهات.
يوجد قواعد لوقت التحويل البرمجي "compile-time" و قواعد لوقت التشغيل "runtime" لعملية التلبيس او القولبة "casting" في جافا.
كيف نقوم بتلبيس او بمعنى آخر قولبة كائنات بواسطة فئة ديناميكيا تم تحميلها
قولبة مراجع الكائنات يعتمد على العلاقة بين الفئات المعنية في نفسه التسلسل الهرمي .
أي مرجع لكائن يمكن أن يسند الى مرجع لمتغير من نوع كائن، وذلك لأن فئة الكائن هي الفئة المتفوقة لكل فئات جافا.
يمكن أن يكون هناك اثنين من سيناريوهات جافا للقولبة

  • Upcasting آب كاستينك
  • Downcasting داون كاستينك


عندما نقولب مرجع على امتداد التسلسل الهرمي انطلاقا من الطبقة الجذرية في اتجاه أحد الفئات الفرعية، يسمى داونكاست. عندما نقولب مرجع على امتداد التسلسل الهرمي انطلاقا من أحد الفئات الفرعية في اتجاه الطبقة الجذرية ، يسمى آبكاست. لا نحتاج إلى استخدام مشغل القولبة في هذه الحالة.
قواعد وقت التحويل البرمجي "compile-time" موجودة لإلتقاط محاولات القولبة في الحالات الغير ممكنة. يحدث هذا عندما نحاول قولبة الكائنات الغير مترابطة تماما (وهذه ليست علاقات لفئة فرعية أو لفئة من الدرجة الاولى أو لواجهة). عند وقت التشغيل يتم طرح ClassCastException إذا كان الكائن الذي سيتم قولبته غير متوافق مع النوع الجديد الذي سيتم القولبة إليه.
أدناه هو مثال يظهر متى يمكن حدوث ClassCastException أثناء قولبة الكائن "object casting"
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
//X is a supper class of Y and Z which are sibblings.

public class RunTimeCastDemo {



public static void main(String args[]) {

X x = new X();

Y y = new Y();

Z z = new Z();

X xy = new Y(); // compiles ok (up the hierarchy)

X xz = new Z(); // compiles ok (up the hierarchy)

// Y yz = new Z(); incompatible type (siblings)

// Y y1 = new X(); X is not a Y

// Z z1 = new X(); X is not a Z

X x1 = y; // compiles ok (y is subclass of X)

X x2 = z; // compiles ok (z is subclass of X)

Y y1 = (Y) x; // compiles ok but produces runtime error

Z z1 = (Z) x; // compiles ok but produces runtime error

Y y2 = (Y) x1; // compiles and runs ok (x1 is type Y)

Z z2 = (Z) x2; // compiles and runs ok (x2 is type Z)

// Y y3 = (Y) z; inconvertible types (siblings)

// Z z3 = (Z) y; inconvertible types (siblings)

Object o = z;

Object o1 = (Y) o; // compiles ok but produces runtime error

}

}

قولبة مراجع الكائن "Object References": قولبة ضمنية باستخدام المحول البرمجي "Compiler"
بشكل عام القولبة الضمنية تتم عندما يتم تعيين مرجع كائن "Object reference" (قولب أو تلبيس) إلى :

  • مرجع المتغير "reference variable" الذي لهو نفس نوع الفئة التي تم إنشاء الكائن منها.
  • الكائن كفئة كائن "Object Class" هي الفئة الفائقة "super class" لكل فئة.
  • مرجع المتغير "reference variable" من نوع الفئة الفائقة "super class" للفئة التي تم إنشاء الكائن منها.
  • مرجع المتغير "reference variable" من نوع واجهة "interface" التي تم تنفيذها "implemented" من قبل الفئة التي تم إنشاء الكائن منها.
  • مرجع المتغير "reference variable" من نوع واجهة "interface" التي تم تنفيذها "implemented" من قبل الفئة الفائقة "super class" للفئة التي تم إنشاء الكائن منها.


ليكن لدينا واجهة "interface" إسمها وسيلة نقل "Vehicle"، و فئة فائقة "super class" إسمها سيارة "Car" و لها فئة فرعية "subclass" إسمها فورد "Ford". المثال التالي يوضح التحويل التلقائي من المراجع الكائن "object references" التي تمت معالجتها بواسطة المحول البرمجي "compiler"
?
1
2
3
4
5
6
7
8
9
10
11
interface Vehicle {

}

class Car implements Vehicle {

}

class Ford extends Car {

}

ليكن "c" متغير من فئة السيارة "Car" و "f" من فئة فورد "Ford" و "v" تكون مرجع الواجهة وسيلة نقل "vehicle ". يمكننا تعيين المرجع "Ford" للمتغير "Car" :

مثال رقم 1
?
1
2
3
4
c = f; //Ok Compiles fine

Where c = new Car();
And, f = new Ford();

المحول البرمجي يعالج تلقائيا عملية التحويل و بما ان الأنواع متوافقة ( علاقة بين فئة فرعية "subclass" و فئة فائقة "super class" ) ، أي نوع "Car" يمكن أن يشتمل نوع "Ford" بما ان "Ford" هي سيارة "Car".
مثال رقم 2
?
1
2
3
4
v = c; //Ok Compiles fine
c = v; // illegal conversion from interface type to class type results in compilation error

Where c = new Car();

التحويل الغير مشروع من النوع واجهة "interface type" إلى النوع فئة "class type" سوف ينتج خطأ في عملية التحويل البرمجي و "v"هو مرجع الواجهة "Vehicle v"
المحول البرمجي يعالج تلقائيا عملية التحويل و بما ان الأنواع متوافقة ( علاقة بين فئة "class" و واجهة "interface" ) ، أي نوع "Car" يمكن أن يقولب "cast to" لنوع "Vehicle interface" بما ان "Car" هي تنفيذ " implements" لــ "Vehicle Interface" (السيارة هي وسيلة نقل).
قولبة مراجع الكائن : القولبة الواضحة
أحيانا نقوم بقولبة واضحة "explicit cast" في جافا عندما تكون القولبة الضمنيا "implicit casts" لا تعمل أو ليست مفيدة لسيناريو معين. القولبة الواضحة "explicit cast" ليست سوى اسم النوع الجديد الموجود بين قوسين. مثل ما كان في السابق، بالنسة لفئة "Car" و الفئة "Ford"
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Car {

void carMethod(){

}

}

class Ford extends Car {

void fordMethod () {

}

}

كما ان لدينا الوظيفة breakingSystem () الذي يأخذ المرجع "Car" (مرجع الفئة الفائقة "Superclass reference" ) كقيمة وسيطة للمدخلات "input parameter".
فإن المنهج يستدعي carMethod () بغض النظر عن نوع الكائن (مرجع "Car" أو مرجع "Ford") وإذا كان هو كائن "Ford"، فإنه سيتم أيضا استدعاء fordMethod (). نستخدم المشغل instanceof لتحديد نوع الكائن في وقت التشغيل.
?
1
2
3
4
5
6
7
8
9
public void breakingSystem (Car obj) {

obj.carMethod();

if (obj instanceof Ford)

((Ford)obj).fordMethod ();

}




لإستدعاء fordMethod ()، العملية "(Ford) obj " تخبر المحول البرمجي "compiler" لعلاج الكائن المشار إليه بواسطة "obj" كما لو أنه كائن "Ford". بدون القولبة فإن المحول البرمجي "compiler" سوف يعطي رسالة خطأ تشير إلى أنه لا يمكن العثور على fordMethod () في تعريف "Car".

يقدم البرنامج التالي توضيح استخدام مشغل القولبة "cast operator" مع المراجع.
ملاحظة : الفئات "Honda" و "Ford" يعتبروا أشقاء في التسلسل الهرمي للفئة. كل من الفئاتين هي فئة فرعية "subclasse"من فئة "Car". كل من الفئة "Car" و الفئة "HeavyVehicle" إمتداد لفئة كائن "Object Class".
فإن أي فئة التي لا تمتد بشكل واضح من بعض فئات أخرى تمتد تلقائيا من كائن "object" افتراضيا. هذا الرمز ينشئ كائن مثيل لفئة "Ford" ويقوم بتعيين مرجع الكائن لمرجع المتغير من نوع "Car".
ويسمح لهذا التعيين على اساس ان "Car" هي الفئة المتفوقة "superclass" لــ "Ford". من أجل استخدام مرجع من نوع فئة لاستدعاء المنهج "method"، يجب تعريف المنهج "method" عند أو أعلى من هذه الفئة في التسلسل الفئة الهرمي.
وبالتالي لا يمكن لكائن من فئة "Car" إستدعاء المنهج "method" موجودة في الفئة "Class Ford" ، حيث أن المنهج fordMethod غير موجود في الفئة "Car" أو اي واحد من الفئة المتفوقة "superclass" لها.
ويمكن بالتالي أن تحل هذه المشكلة بواسطة دونكاسة "downcast" بسيط عن طريق قولبة مرجع الكائن "Car" الى مرجع الفئة "Ford" كما فعلنا في البرنامج.
أيضا محاولة قولبة مرجع كائن الى مرجع الكائن الشقيق له تنتج ClassCastException في وقت التشغيل، على الرغم من ان عملية التحويل البرمجي تحدث من دون أي خطأ.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Car extends Object{

void carMethod() {

}

}



class HeavyVehicle extends Object{



}



class Ford extends Car {

void fordMethod () {

System.out.println("I am fordMethod defined in Class Ford");

}

}



class Honda extends Car {

void fordMethod () {

System.out.println("I am fordMethod defined in Class Ford");

}

}



public class ObjectCastingEx{

public static void main(

String[] args){

Car obj = new Ford();

// Following will result in compilation error

// obj.fordMethod(); //As the method fordMethod is undefined for the Car Type

// Following will result in compilation error

// ((HeavyVehicle)obj).fordMethod(); //As the method fordMethod is undefined for the HeavyVehicle Type

// Following will result in compilation error



((Ford)obj).fordMethod();



//Following will compile and run

// Honda hondaObj = (Ford)obj; Cannot convert from Ford to Honda as they are sibblings



}

}

أحد عمليات القولبة الاكثر شيوعا التي يتم تنفيذها عند التعامل مع المجموعات، يمكنك قولبة مرجع كائن إلى سلسلة الأغراض "String"
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*

One common casting that is performed when dealing with collections is, you can cast an object reference into a String.

Below is an example that shows how you can cast an object retrieved from a vector of objects into a String.



*/



import java.util.Vector;



public class StringCastDemo{

public static void main(String args[]){

String username = "asdf";

String password = "qwer";

Vector v = new Vector();

v.add(username);

v.add(password);





// String u = v.elementAt(0); Cannot convert from object to String

Object u = v.elementAt(0); //Cast not done

System.out.println("Username : " +u);





String uname = (String) v.elementAt(0); // cast allowed

String pass = (String) v.elementAt(1); // cast allowed



System.out.println();

System.out.println("Username : " +uname);

System.out.println("Password : " +pass);

}

}




Output
Username: asdf
Username : asdf
Password : qwer


عامل التشغيل "instanceof"
عامل التشغيل "instanceof" يسمى بمشغل مقارنة النوع ، يتيح لك تحديد ما إذا كان كائن ينتمي إلى فئة معينة، أو تنفيذ لواجهة معينة. فإنها تعود بصحيح "true" إذا كان الكائن هو مثيل لفئة "instance of the class" أو إذا كان الكائن تنفيذ لواجهة "implements the interface"، وإلا فإنها تعود بــ false.
أدناه هو مثال يوضح استخدام المشغل instanceof
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/*

One common casting that is performed when dealing with collections is, you can cast an object reference into a String.

Below is an example that shows how you can cast an object retrieved from a vector of objects into a String.



*/



import java.util.Vector;



public class StringCastDemo{

public static void main(String args[]){

String username = "asdf";

String password = "qwer";

Vector v = new Vector();

v.add(username);

v.add(password);





// String u = v.elementAt(0); Cannot convert from object to String

Object u = v.elementAt(0); //Cast not done

System.out.println("Username : " +u);





String uname = (String) v.elementAt(0); // cast allowed

String pass = (String) v.elementAt(1); // cast allowed



System.out.println();

System.out.println("Username : " +uname);

System.out.println("Password : " +pass);

}

}

Output
hV is an HeavyVehicle: true
T is an HeavyVehicle: true
hV is a Truck: false
hv2 is an HeavyVehicle: false
ملاحظة : hv2 ليس له مرجعية الى حد الان لكائن "HeavyVehicle" و ترجع instanceof بــ false. كما أننا لا نستطيع استخدام المشغل instanceof مع الفئات الأشقاء.