La généricité en Java (suite)

Transcription

La généricité en Java (suite)
La généricité en Java (suite)
F. Barthélemy
14 mars 2006
1
Rappel : exemple simple
c l a s s L i s t e <T>{
boolean e s t V i d e ( ) {
return true ;
}
L i s t e <T> s u i t e ( )
throws L i s t e V i d e E x c e p t i o n {
throw L i s t e V i d e E x c e p t i o n . exc ;
}
T t e t e ( ) throws L i s t e V i d e E x c e p t i o n {
throw L i s t e V i d e E x c e p t i o n . exc ;
}
}
c l a s s ListeNonVide <T> extends L i s t e <T>{
T premier ;
L i s t e <T> s u i v a n t ;
ListeNonVide (T p , L i s t e <T> s ){
premier = p ;
suivant = s ;
}
boolean e s t V i d e ( ) {
return f a l s e ;
}
L i s t e <T> s u i t e ( ) throws L i s t e V i d e E x c e p t i o n {
return s u i v a n t ;
}
T t e t e ( ) throws L i s t e V i d e E x c e p t i o n {
return p r e m i e r ;
}
}
c l a s s L i s t e V i d e E x c e p t i o n extends Exception {
s t a t i c L i s t e V i d e E x c e p t i o n exc =
new L i s t e V i d e E x c e p t i o n ( ) ;
}
1
c l a s s Autre {
s t a t i c int l o n g u e u r ( L i s t e <?> l )
throws L i s t e V i d e E x c e p t i o n {
int r e s = 0 ;
while ( ! l . e s t V i d e ( ) ) {
r e s ++;
l = l . suite ();
}
return r e s ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s )
throws L i s t e V i d e E x c e p t i o n {
L i s t e <I n t e g e r > l a l = new L i s t e <I n t e g e r > ( ) ;
l a l = new ListeNonVide<I n t e g e r >(5 , l a l ) ;
l a l = new ListeNonVide<I n t e g e r >(7 , l a l ) ;
System . out . p r i n t l n ( l o n g u e u r ( l a l ) ) ;
}
}
class TesteListe {
public s t a t i c void main ( S t r i n g [ ] a r g s )
throws L i s t e V i d e E x c e p t i o n {
L i s t e <S t r i n g > l s = new L i s t e <S t r i n g > ( ) ;
l s = new ListeNonVide <S t r i n g >(” a r t ” , l s ) ;
l s = new ListeNonVide <S t r i n g >(” gosh ” , l s ) ;
L i s t e <S t r i n g > l t = new L i s t e <S t r i n g > ( ) ;
l t = new ListeNonVide <S t r i n g >(”jam” , l t ) ;
l t = new ListeNonVide <S t r i n g >( l s . t e t e ( ) , l t ) ;
ls = ls . suite ();
}
}
2
Sécurité apportée par la généricité
Première version : utilisation générique de la classe générique Liste.
c l a s s ErreurTypage{
public s t a t i c void main ( S t r i n g [ ] a r g s ){
L i s t e <S t r i n g > l = new L i s t e <S t r i n g > ( ) ;
l = new ListeNonVide<S t r i n g >(” o u i ” , l ) ;
l = new ListeNonVide<S t r i n g >(new I n t e g e r ( 4 ) , l ) ;
}
}
/∗
> javac Liste . java
L i s t e . j a v a : 3 8 : cannot f i n d symbol
symbol : c o n s t r u c t o r ListeNonVide ( j a v a . l a n g . I n t e g e r ,
2
L i s t e <j a v a . l a n g . S t r i n g >)
l o c a t i o n : c l a s s ListeNonVide<j a v a . l a n g . S t r i n g >
l = new ListeNonVide<S t r i n g >(new I n t e g e r ( 4 ) , l ) ;
ˆ
1 error
∗/
Et si l’on utilise la classe sans spécifier le paramètre générique, le code se compile, mais il
y a un avertissement.
c l a s s ErreurTypageBis{
public s t a t i c void main ( S t r i n g [ ] a r g s ){
L i s t e l = new L i s t e ( ) ;
l = new ListeNonVide ( ” o u i ” , l ) ;
l = new ListeNonVide (new I n t e g e r ( 4 ) , l ) ;
}
}
> javac L i s t e . java
Note : L i s t e . j a v a u s e s unchecked or u n s a f e o p e r a t i o n s .
Note : Recompile with − X l i n t : unchecked for d e t a i l s .
> j a v a c − X l i n t : unchecked L i s t e . j a v a
L i s t e . j a v a : 4 4 : warning : [ unchecked ] unchecked c a l l to
ListeNonVide (T, L i s t e <T>) as a member o f the raw type ListeNonVide
l = new ListeNonVide ( ” o u i ” , l ) ;
ˆ
L i s t e . j a v a : 4 5 : warning : [ unchecked ] unchecked c a l l to ListeNonVide (T, L i s t e <T>)
l = new ListeNonVide (new I n t e g e r ( 4 ) , l ) ;
ˆ
2 warnings
3
Exemples de généricité dans la librairie
Voici des exemples issus de la librairie.
public i n t e r f a c e Comparable<T>{
int compareTo (T o ) ;
}
public i n t e r f a c e I t e r a b l e <T>{
I t e r a t o r <T> i t e r a t o r ( ) ;
}
public i n t e r f a c e I t e r a t o r <E>{
boolean hasNext ( ) ;
E next ( ) ;
void remove ( ) ;
}
public f i n a l c l a s s I n t e g e r extends Number
implements Comparable<I n t e g e r >{
3
...
public s t a t i c int bitCount ( int i ) ;
public int compareTo ( I n t e g e r a n o t h e r I n t e g e r ) ;
...
}
public c l a s s Vector<E> extends A b s t r a c t L i s t <E>
implements L i s t <E > , . . . {
...
public Vector ( C o l l e c t i o n <? extends E> c ) ;
...
public boolean add (E o ) ;
public boolean remove ( Object o ) ;
public E f i r s t E l e m e n t ( ) ;
public boolean c o n t a i n s A l l ( C o l l e c t i o n <?> c ) ;
...
}
4
Des exemples compliqués
import j a v a . u t i l . ∗ ;
c l a s s UnPeuComplique<A, B extends Vector<A>>{
B var ;
UnPeuComplique (B b ){
var = b ;
}
void v i d e ( ) {
var . c l e a r ( ) ;
}
public s t a t i c void main ( S t r i n g [ ] a r g s ){
Vector<I n t e g e r > v = new Vector<I n t e g e r > ( ) ;
v . add ( 4 ) ;
(new UnPeuComplique<I n t e g e r , Vector<I n t e g e r >>(v ) ) . v i d e ( ) ;
}
}
c l a s s Complique<A extends Comparable<A>,B extends Vector<A>>{
void m(B leb , A l e a ){
i f ( l e a . compareTo ( l e b . f i r s t E l e m e n t ())==0){
System . out . p r i n t l n ( ” I l s s o n t egaux ” ) ;
}
}
public s t a t i c void main ( S t r i n g [ ] a r g s ){
Vector<I n t e g e r > v = new Vector<I n t e g e r > ( ) ;
v . add ( 4 ) ;
(new Complique<I n t e g e r , Vector<I n t e g e r > >()).m( v , 4 ) ;
}
4
}
5
Ce qui ne marche pas
On ne peut pas instancier un objet ou un tableau avec un paramètre de type.
On ne peut pas non plus utiliser un paramètre de type dans une méthode ou une variable
statique.
c l a s s Tableau<T>{
T[ ] t ;
T v;
s t a t i c T v2 ;
void m( ) {
t = new T [ 1 0 ] ;
v = new T ( ) ;
}
static T n(){
return null ;
}
}
/∗
> j a v a c TabGen . j a v a
TabGen . j a v a : 4 : non−s t a t i c c l a s s T cannot be r e f e r e n c e d from a s t a t i c c o n t e x t
s t a t i c T v2 ;
ˆ
TabGen . j a v a : 9 : non−s t a t i c c l a s s T cannot be r e f e r e n c e d from a s t a t i c c o n t e x t
s t a t i c T n(){
ˆ
TabGen . j a v a : 6 : g e n e r i c a r r a y c r e a t i o n
t = new T [ 1 0 ] ;
ˆ
TabGen . j a v a : 7 : u n e x p e c t e d t y p e
found
: t y p e parameter T
required : class
v = new T ( ) ;
ˆ
4 errors
∗/
La solution : passer les objets et tableaux en paramètre au constructeur ou faire des
contorsions.
Autres choses qui ne marchent pas : les tests dynamiques. Par exemple instanceof et le
cast.
import j a v a . u t i l . ∗ ;
c l a s s MarchePas<T>{
5
T lameth ( Object o ){
return (T) o ;
}
method m( Vector v ){
i f ( v instanceof Vector<S t r i n g >){
System . out . p r i n t l n ( ”C ’ en e s t un” ) ;
}
}
public s t a t i c void main ( S t r i n g [ ] a r g s ){
Vector v = new Vector ( ) ;
I t e r a b l e <S t r i n g > t = ( I t e r a b l e <S t r i n g >) v ;
}
}
/∗
> j a v a c − X l i n t : unchecked MarchePas . j a v a
MarchePas . j a v a : 6 : cannot f i n d symbol
symbol : c l a s s method
l o c a t i o n : c l a s s MarchePas<T>
method m( Vector v ){
ˆ
MarchePas . j a v a : 4 : warning : [ unchecked ] unchecked c a s t
found
: java . lang . Object
required : T
r e t u r n (T) o ;
ˆ
MarchePas . j a v a : 7 : i l l e g a l g e n e r i c t y p e f o r i n s t a n c e o f
i f ( v i n s t a n c e o f Vector<S t r i n g >){
ˆ
MarchePas . j a v a : 1 3 : warning : [ unchecked ] unchecked c a s t
found
: j a v a . u t i l . Vector
r e q u i r e d : j a v a . l a n g . I t e r a b l e <j a v a . l a n g . S t r i n g >
I t e r a b l e <S t r i n g > t = ( I t e r a b l e <S t r i n g >) v ;
ˆ
2 errors
2 warnings
∗/
6
Une chose surprenante
Quand on donne plusieurs bornes supérieures à un paramètre de type, on ne peut pas
toujours utiliser toutes les opérations de ces bornes supérieures.
interface L i s i b l e {
void l i t ( ) ;
}
interface Extensible {
6
void etend ( ) ;
}
abstract c l a s s B l a b l a {
abstract void c a u s e ( ) ;
abstract int d e g r e ( ) ;
abstract B l a b l a l e P l u s B e a u ( B l a b l a b ) ;
}
c l a s s UneBorne<T extends Blabla >{
void m(T para ){
para . c a u s e ( ) ;
para . l e P l u s B e a u ( null ) ;
}
}
c l a s s DeuxBornes<T extends B l a b l a & L i s i b l e >{
void m(T para ){
para . l i t ( ) ;
para . c a u s e ( ) ;
para . l e P l u s B e a u ( para ) ;
}
}
c l a s s DeuxBornesBis<T extends B l a b l a & L i s i b l e & E x t e n s i b l e >{
void m(T para ){
para . l i t ( ) ;
para . etend ( ) ;
}
}
/∗
> j a v a c DeuxBornes . j a v a
DeuxBornes . j a v a : 2 1 : cannot f i n d symbol
symbol : method cause ( )
para . cause ( ) ;
ˆ
DeuxBornes . j a v a : 2 2 : cannot f i n d symbol
symbol : method l e P l u s B e a u (T)
para . l e P l u s B e a u ( para ) ;
ˆ
2 errors
∗/
Voyons les codes décompilés de ces classes :
//
//
//
//
Decompiled by Jad v1 . 5 . 8 e . C o p y r i g h t 2 0 0 1 P a v e l Kouznetsov .
Jad home page : h t t p : / /www . g e o c i t i e s . com/ kpdus / j a d . html
Decompiler o p t i o n s : p a c k i m p o r t s ( 3 )
Source F i l e Name :
DeuxBornes . j a v a
c l a s s UneBorne
7
{
UneBorne ( )
{
}
void m( B l a b l a b l a b l a )
{
blabla . cause ( ) ;
b l a b l a . l e P l u s B e a u ( null ) ;
}
}
//
//
//
//
Decompiled by Jad v1 . 5 . 8 e . C o p y r i g h t 2 0 0 1 P a v e l Kouznetsov .
Jad home page : h t t p : / /www . g e o c i t i e s . com/ kpdus / j a d . html
Decompiler o p t i o n s : p a c k i m p o r t s ( 3 )
Source F i l e Name :
DeuxBornes . j a v a
c l a s s DeuxBornes
{
DeuxBornes ( )
{
}
void m( B l a b l a b l a b l a )
{
(( Lis ibl e ) blabla ) . l i t ( ) ;
}
}
//
//
//
//
Decompiled by Jad v1 . 5 . 8 e . C o p y r i g h t 2 0 0 1 P a v e l Kouznetsov .
Jad home page : h t t p : / /www . g e o c i t i e s . com/ kpdus / j a d . html
Decompiler o p t i o n s : p a c k i m p o r t s ( 3 )
Source F i l e Name :
DeuxBornes . j a v a
c l a s s DeuxBornesBis
{
DeuxBornesBis ( )
{
}
void m( L i s i b l e l i s i b l e )
{
lisible . lit ();
( ( E x t e n s i b l e ) l i s i b l e ) . etend ( ) ;
8
}
}
9

Documents pareils